How to write a unit test with data fetching, that alters data based on respone in vuejs? - unit-testing

I am trying to write a unit test for a function that does an async call, but it doesnt seem to alter the data prop, maybe I am doing something wrong.
Check the code below:
getSomething() {
MyService.getThis().then(
response => {
this.status = true;
}
).catch(error => {})
}
TestCase:
describe('test', () => {
beforeEach(() => {
// To ignore the created hook, but this doesnt work, any idea?
spyOn(CustomerData, 'created');
spyOn(MyService, 'getThis').and.returnValue(Promise.resolve(list));
});
wrapper = shallowMount(MyComponent, {
propsData: {
data: {}
},
});
it('should work', () => {
wrapper.vm.getSomething();
expect(wrapper.vm.status).toBeTruthy();
});
});
}
The status should be true, but it is false, but if I print the value of status in the getSomething() function it is indeed true. I have no idea what the issue can be.
update:
In the test case I wrote
it('should work', async () => {
await wrapper.vm.getSomething();
expect(wrapper.vm.status).toBeTruthy();
}
and this seems to work. Is this a good way to solve it? Would love to hear other solutions.
Also I am very interested if it is possible to ignore the created hook, I havent been able to figure that out yet.

Code that running inside getSomething() is asynchronous. MyService.getThis() returns promise, and its execution takes time, in case if you fetching some data from remote serivce.
So first of all you need to return promise from getSomething()
getSomething() {
return MyService.getThis()
.then(response => { this.status = true; })
.catch(error => {})
}
And inside the test you need to return promise outside, to let jest know that your test is asynchronous.
it('should work', () => {
return wrapper.vm.getSomething().then(() => {
expect(wrapper.vm.status).toBeTruthy();
});
});
Or as you mentioned in the edited part you can use async version:
it('should work', async () => {
await getSomething();
expect(wrapper.vm.status).toBeTruthy();
});

Related

How can I test a function that use a promise?

how can I test a function that call a promise ?
click() {
this.todoService.getUsers().then(
(resp) => {
this.users = resp;
},
(reject) => {
console.log(reject);
}
);
}
I tried this , but the console return undeefined
it('should get all users', () => {
const users =[....]
todoServiceSpy.getUsers.and.returnValue(of(users).toPromise());
component.click();
console.log('component.users', component.users);
expect(component.users).toEqual(users);
I'm new in testings
You can use async/fixture.whenStable() to wait for the promises in queue to complete before proceeding.
// add async here
it('should get all users', async () => {
const users =[....]
todoServiceSpy.getUsers.and.returnValue(of(users).toPromise());
component.click();
// !! wait for all promises in queue to complete before proceeding
await fixture.whenStable();
console.log('component.users', component.users);
// do assertions
expect(component.users).toEqual(users);
You can also use fakeAsync/tick. I suggest you read up on these methodologies.
It explains some of it here: https://www.digitalocean.com/community/tutorials/angular-testing-async-fakeasync.

Check if a stubbed getter function has been called with sinon spy

I am using firebase admin and I am trying to write some unit tests for my code.
Since admin is injected in my function I figured I could mock a very simple object like this:
admin = {
get auth () {
return {
updateUser: () => {
return true;
},
createUser: () => {
return true;
},
getUser: () => {
throw Error('no user');
}
};
}
};
Then in a particular test I can stub the functions. Here is what I have done so far:
// stubbed functions
sinon.stub(admin, 'auth').get(() => () => ({
updateUser: () => ({ called: true }),
getUser: () => (userRecord),
createUser: () => ({ called: false })
}));
and those are working fine (I can see with my logs).
However in my test I would also want to check if createUser has been called at all.
I thought I could set up a spy on the createUser function, but so far I can't really get it to work.
Here is what I have been trying (with a bunch of variation always failing):
it.only('should update a user', async () => {
const userRecord = mockData
sinon.stub(admin, 'auth').get(() => () => ({
updateUser: () => ({ called: true }),
getUser: () => (userRecord),
createUser: () => ({ called: false })
}));
const spy = sinon.spy(admin, 'auth', ['get']); // this is not working
const user = await upsertUser(data, firestore, admin);
expect(user).toEqual(data.userDataForAuth); // this one is ok
sinon.assert.calledOnce(spy.get); // this throws an error
});
the bit of code I am trying to test (which is the upsert function is this:
// in my test exisiting user is not null (the stub `getUser` is returning a object
if (existingUser != null) {
try {
await admin.auth().updateUser(uid, userDataForAuth);
return userDataForAuth;
} catch (error) {
console.log('error', error);
throw Error('error updating user');
}
}
I am not even sure this is the best approach, happy to change it if there is a better one!

How can i coverage a promise response with Jasmine and Karma

I have a function that returns and treats a promise, I need to cover the return that is inside then but I don't know how I can do this, I'm currently trying as follows:
confirmRemoveUser(user: IUser) {
this.modalService
.open('Confirma a exclusão do usuário selecionado?', {
titleText: 'Confirmando exclusão',
confirmButtonText: 'Sim',
cancelButtonText: 'Cancelar',
closeButtonText: 'Fechar',
buttonType: 'danger'
})
.result.then(
(result: BentoModalConfirmationCloseReason) => {
if (result === BentoModalConfirmationCloseReason.Confirm) {
if (this.removeUser(user)) {
this.toastService.open('Usuário excluído com sucesso!', { type: 'success', close: true });
} else {
this.toastService.open('Falha ao excluir o usuário!', { type: 'warning', close: true, duration: 0 });
}
}
}
);
}
I'm currently using callthrough () and imagine that with some parameter I can get the promise but I don't know how:
it('Given_ConfirmRemoveUser_When_UserStepIsCalled_Then_UserIsRemoved', (done) => {
component.selectedJob = {
};
component.selectedArea = {
};
component.users = [{
}];
spyOn(modalService, 'open').withArgs('This is modal msg').and.callThrough();
component.confirmRemoveUser(component.users[0]);
expect(modalService.open).toHaveBeenCalled();
done();
});
And my coverage is like the image below:
Image here!
UPDATE
New Error
Your test should work when it is rewritten as follows:
it('Given_ConfirmRemoveUser_When_UserStepIsCalled_Then_UserIsRemoved', (done) => {
spyOn(modalService, 'open').and.returnValue(Promise.resolve(BentoModalConfirmationCloseReason.Confirm));
spyOn(toastService, 'open').and.stub();
component.confirmRemoveUser(component.users[0])
.then(r => {
expect(toastService.open).toHaveBeenCalled();
done();
})
.catch(e => fail(e));
});
You probably also want to know what will be displayed in the toast. Therefore it makes sense to rather use expect(toastService.open).toHaveBeenCalledWith(?);.
UPDATE
Above solution only works if confirmRemoveUser would return a Promise.
confirmRemoveUser(user: IUser) {
return this.modalService
...
In your case, the use of the done function does not make sense. You need to use async and await.
it('Given_ConfirmRemoveUser_When_UserStepIsCalled_Then_UserIsRemoved', async () => {
spyOn(modalService, 'open').and.returnValue(Promise.resolve(BentoModalConfirmationCloseReason.Confirm));
spyOn(toastService, 'open').and.stub();
await component.confirmRemoveUser(component.users[0]);
expect(toastService.open).toHaveBeenCalled();
});
The same can be achieved with fakeAsync and flush.
import { fakeAsync, flush } from '#angular/core/testing';
...
it('Given_ConfirmRemoveUser_When_UserStepIsCalled_Then_UserIsRemoved', fakeAsync(() => {
spyOn(modalService, 'open').and.returnValue(Promise.resolve(BentoModalConfirmationCloseReason.Confirm));
spyOn(toastService, 'open').and.stub();
component.confirmRemoveUser(component.users[0]);
flush();
expect(toastService.open).toHaveBeenCalled();
}));

Jest test redux action with thunk doesn't cover statemets

Hello i have been trying to test a function with thunk and all the test passes but can't figure it out why the coverage doesn't not update or the test function does not cover the statement.
This is my function:
export const setFinished = (campaignId, userId, actionId, callback) => {
return async (dispatch, getState) => {
await axios.post(`http://bazuca.com:9000/campaigns/${campaignId}/progress`, {
userId,
actionId
}, { headers: { token: getState().app.token } })
.then((response) => {
})
.catch((error) => {
})
callback();
}
}
This is my last test (I have done like 3 different types and cant get the coverage to work)
describe("setFinished", () => {
it("works", () => {
const dispatch = jest.fn();
const callback = jest.fn(() => 'callback');
const getState = jest.fn();
let a = setFinished(1, 1, 1, callback)
expect(a).toHaveBeenCalledWith(1, 1, 1, callback);
a(dispatch, getState);
expect(callback).toHaveBeenCalled();
});
});
and i just get this in the coverage:
Maybe im doing it wrong? or should use another library?
There might be some things missing in your test setup. Especially the way you're making an assertion about the dispatch mock looks unusual. Without going into too much detail, just consider the following:
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { setFinished } from 'path/to/your/actions';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('setFinished', () => {
it('works', () => {
// You have to make sure axios calls are mocked out properly
// at this point. I don't have a snippet handy for this so I
// left it out. But it would be similar to the following:
axios.mockImplementationOnce(() => ({
// Let the promise return whatever your response is for a
// positive test case
post: () => Promise.resolve({ isFinished: true })
}));
const expected = [
// I'm assuming something like this is dispatched in the
// .then handler of your action:
{ type: 'SET_FINISHED_SUCCESS' }
];
const store = mockStore({});
// Mock some arguments here
return store.dispatch(setFinished(1, 2, 3, () => null))
.then(() => expect(store.getActions()).toEqual(expected));
});
});
If axios is mocked out correctly, this will definitely achieve 100% coverage for this action if you also add a negative test case for the catch block.

How to mock pg-promise library with jest

I am trying to mock the pg promise library. I want to be able mock return whether the promise rejects or resolves. Here is an example function and test:
const pgp = require('pg-promise')({});
const someFunc = callback => {
const db = pgp('connectionString');
db
.none('create database test;')
.then(() => {
callback(null, 'success');
})
.catch(err => {
callback(err);
});
};
module.exports = {
someFunc
};
And i wanna test it like so:
const { someFunc } = require('./temp');
let pgp = require('pg-promise')({
noLocking: true
});
// HOW TO MOCK?
describe('test', () => {
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
});
it('should test', () => {
let db = pgp('connectionString');
// how to mock this?
db.none = jest.fn();
db.none.mockReturnValue(Promise.reject('mock'));
const callback = jest.fn();
someFunc(callback);
return new Promise(resolve => setImmediate(resolve)).then(() => {
expect(callback.mock.calls.length).toEqual(1);
});
});
});
You can mock the pgp object with a dumb mock like so:
const { someFunc } = require('./temp');
let pgp = jest.fn(() => ({
none: jest.fn(),
})
jest.mock('pg-promise') // Jest will hoist this line to the top of the file
// and prevent you from accidentially calling the
// real package.
describe('test', () => {
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
});
it('should test', () => {
let db = pgp('connectionString');
db.none.mockRejectedValue('mock'); // This is the mock
const callback = jest.fn();
someFunc(callback);
return new Promise(resolve => setImmediate(resolve)).then(() => {
expect(callback.mock.calls.length).toEqual(1);
});
});
});
Its an old question, but here is a new answer:
You can have a look at pg-mem, a library I released recently which emulates an in-memory postgres instance.
It supports most of the usual SQL queries (but will fail on less frequent syntaxes - file an issue if you encounter such a situation).
I wrote an article about it here
For your use case, see the this section