Currently I have the following piece of code:
function handleConnection(socket: Socket): void {
info(`Connection started with socketId: ${socket.id}`)
socket.on("joinRoom", (request: string) => handleJoinRoom(socket, request));
socket.on("shareData", (request: IShareDataRequest) => handleShareData(socket, request));
socket.on("disconnect", () => handleDisconnect(socket));
}
I want to write a test for each and every events like joinRoom, shareData and disconnect. To isolae the tests I want to only test the second socket.on("shareData", () => ...) call and skip the first socket.on("joinRoom", () => ...) call. I've tried with multiple mockImplementationOnce methods with no success.
The test I wrote:
it('should emit data to room', () => {
const listenMock = listen();
const socketMock = {
on: jest.fn()
.mockImplementationOnce(() => null)
.mockImplementationOnce((event: string, callback: Function) => callback({ roomId: "abcdefg" })),
to: jest.fn().mockReturnValue({
emit: jest.fn()
})
}
jest.spyOn(listenMock, "on").mockImplementationOnce((event: string, callback: Function) => callback(socketMock))
startSocket();
expect(socketMock.to).toHaveBeenCalledWith("abcdefg");
expect(socketMock.to().emit).toHaveBeenCalledWith("receiveData", expect.any(Object));
})
ShareData function:
function handleShareData(socket: Socket, request: IShareDataRequest): void {
socket.to(request.roomId).emit("receiveData", request);
}
I would really appreciate if anyone could help me out with this.
You can try the following approach:
// define the mockSocket
const mockSocket = {
// without any implementation
on: jest.fn()
};
describe("connection handler", () => {
// I personally like separating the test setup
// in beforeAll blocks
beforeAll(() => {
handleConnection(mockSocket);
});
// you can write assertions that .on
// should have been called for each event
// with a callback
describe.each(["joinRoom", "shareData", "disconnect"])(
"for event %s",
event => {
it("should attach joinRoom handlers", () => {
expect(mockSocket.on.mock.calls).toEqual(
expect.arrayContaining([[event, expect.any(Function)]])
);
});
}
);
describe("joinRoom handler", () => {
beforeAll(() => {
// jest mock functions keep the calls internally
// and you can use them to find the call with
// the event that you need and retrieve the callback
const [_, joinRoomHandler] = mockSocket.on.mock.calls.find(
([eventName]) => eventName === "joinRoom"
);
// and then call it
joinRoomHandler("mockRequestString");
});
it("should handle the event properly", () => {
// your joinRoom handler assertions would go here
});
});
});
Related
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.
I'm trying to mock function that has a stream return type and callback as arg. I get timeout because the call back function never get called.
This is the function I'm trying to test:
public setServerUrls(): Observable<void> {
const obs: Observable<void> = new Observable((observer: Observer<void>) => {
const stream: ClientWritableStream<Util.Server> = this.fileTransferClient.setURLs((error: ServiceError, response) => {
if (error) {
observer.error(`TransferManager Electron: unable to set server urls error: ${error.message}.`);
}
observer.next();
observer.complete();
logger.info(`TransferManager Electron: setting URLs completed.`);
});
const transferRequest = new Util.Server();
transferRequest
.setIp('localhost')
.setTransferport('9092')
.setUuid('4020a522-81fe-4996-b637-0620ae656d29');
stream.write(transferRequest);
stream.end();
});
return obs;
}
My jasmine setup:
const settingStream = {
write: () => { },
end: () => { }
};
const callBack = () => {
return;
};
const f = function (callback: Function): any {
return settingStream;
};
mockFileTransferClient = jasmine.createSpyObj('FileTransferClient', {
subscribe: () => mockFileTransferStream,
uploadFile: () => duplexStream,
setURLs: f(callBack)
});
mockFileTransferClientWrapper.createNewFileTransferClient.and.returnValue(mockFileTransferClient as any);
// Question here... does not work!
mockFileTransferClient.setURLs.and.returnValue(settingStream);
test:
it('should set urls', done => {
transferManager.setServerUrls()
.subscribe(
x => {
expect(x).toBeDefined();
done();
}
);
});
This is Elctron + grpc functionality test.
Test timeout because it never gets into the callback and observable never completes.
I'm not sure how to mock setURLs with return value AND callback.
You have to first mock your setUrls to return a resolved observable.
I think what you need here is to use fakeAsync() functionality as you are dealing with async test. Using Tick with fakeAsync ensures that all pending asynchronous activities will finish. In your case it will wait for setTimeout.
Note that you should also inject the setServerUrls using TestBed.inject...
So I think your tests should look like this
it("should .....", fakeAsync(() => {
// Arrange - mock functions
// Act - Make a call to the function
// Use tick() after making call to the function which will flush your setTimeouts
// Assert
}));
For more information, see the fakeAsync documentation
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!
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.
I am testing a angular component and the code is
ngOnInit(): void {
this.getNar();
}
getNar(): void {
let self = this;
this.dashboardService.getNar().subscribe(
res => self.narIds = res.narIds,
error => self.error = error,
function () {
self.narIds.forEach(element => {
// Some Code
});
}
);
}
The Service provider for this i.e Dashboard Service is
getNar(): Observable<any> {
return this.http.get(Config.Api.GetNar + '1/nar').map((res: Response) => res.json());
}
And my Test cases are:
let res = '"narIds":[{"id":1,"narId":"104034-1","narName":"SDLC Platform"},{"id":2,"narId":"64829-1","narName":"EMS-EMS"}]';
describe('Application Health Component', () => {
beforeEach( async(() => {
TestBed.configureTestingModule({
providers: [MockBackend, DashboardService],
imports: [ChartsModule, SlimScrollModule, HttpModule],
declarations: [CompletedFilterPipe, ApplicationHealthComponent]
})
.compileComponents()
.then(createComponent);
}));
it('should call the getNar when ngOnInit is called', async(() => {
spyOn(dashboardService, 'getNar').and.returnValue(Observable.of(res));
comp.ngOnInit();
expect(dashboardService.getNar).toHaveBeenCalled();
}));
});
function createComponent() {
fixture = TestBed.createComponent(ApplicationHealthComponent);
comp = fixture.componentInstance;
dashboardService = fixture.debugElement.injector.get(DashboardService);
};
The problem I am getting is the test case gives an error that forEach is undefined.
The error message is not that forEach function is not defined, it's that your object "self.narIds" is undefined. Fairly sure this is due to the way you declared your onComplete function in Observable.subscribe
related to this Rx Subscribe OnComplete fires but cannot use the data
change your
function () {
self.narIds.forEach(element => {
// Some Code
});
code to
() => {
self.narIds.forEach(element => {
// Some Code
});