SinonStub function observer - javascript

I try to test express middleware through sinon.js
I wanna test, that it send to response specific JSON and don't let request go to next middleware or request handler.
const middleware = (req: Request, res: Response, next: NextFunction) => {
setTimeout(() => res.json({status: 'blocked'}), 1000);
}
For mocking Request and Response I use sinon-express-mock. So every property and method in Response object is SinonStub
My problem is, that when I call middleware and method json is called, I don't know, how to check it, after it's called.
Is there some listener or Observer on SinonStub?
Thank you.

Here is the unit test solution:
index.ts:
import { NextFunction, Response, Request } from 'express';
const middleware = (req: Request, res: Response, next: NextFunction) => {
setTimeout(() => res.json({ status: 'blocked' }), 1000);
};
export { middleware };
index.test.ts:
import { middleware } from './';
import { Request } from 'express';
import sinon, { SinonFakeTimers } from 'sinon';
describe('56676480', () => {
let clock: SinonFakeTimers;
before(() => {
clock = sinon.useFakeTimers();
});
after(() => {
clock.restore();
});
it('should pass', () => {
const mReq = {} as Request;
const mRes = { json: sinon.stub() } as any;
const mNext = sinon.stub();
middleware(mReq, mRes, mNext);
clock.tick(1000);
sinon.assert.calledWithExactly(mRes.json, { status: 'blocked' });
});
});
unit test results with 100% coverage:
56676480
✓ should pass
1 passing (12ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------

Related

How to mock nanoid for testing?

I'm trying to mock nanoid for my testing but it doesn't seem to be working.
my function
public async createApp(appDto: ApplicationDto): Promise<string> {
const appWithToken = { ...appDto, accessToken: nanoid() };
const application = await this.applicationModel.create(appWithToken);
return application.id;
}
My test:
beforeEach(() => {
mockRepository.create.mockResolvedValueOnce({ id: mockId });
});
test("creates application and returns an id", async () => {
const mockAppDto: ApplicationDto = { email: "123#mock.com" };
const application = await applicationService.createApplication(mockAppDto);
expect(mockRepository.create).toHaveBeenCalledWith(mockAppDto); //how do I mock the nanoid here?
expect(application).toBe(mockId);
});
So basically I'm struggling to figure out how to mock the nanoid which is generated inside the function.
I've tried the following at the top of the file:
jest.mock('nanoid', () => 'mock id');
however it doesn't work at all.
Any help would be appreciated!
You didn't mock the nanoid module correctly. It uses named exports to export the nanoid function.
Use jest.mock(moduleName, factory, options) is correct, the factory argument is optional. It will create a mocked nanoid function.
Besides, you can use the mocked function from ts-jest/utils to handle the TS type.
E.g.
Example.ts:
import { nanoid } from 'nanoid';
export interface ApplicationDto {}
export class Example {
constructor(private applicationModel) {}
public async createApp(appDto: ApplicationDto): Promise<string> {
const appWithToken = { ...appDto, accessToken: nanoid() };
const application = await this.applicationModel.create(appWithToken);
return application.id;
}
}
Example.test.ts:
import { nanoid } from 'nanoid';
import { Example, ApplicationDto } from './Example';
import { mocked } from 'ts-jest/utils';
jest.mock('nanoid');
const mnanoid = mocked(nanoid);
describe('67898249', () => {
afterAll(() => {
jest.resetAllMocks();
});
it('should pass', async () => {
mnanoid.mockReturnValueOnce('mock id');
const mockAppDto: ApplicationDto = { email: '123#mock.com' };
const mockApplicationModel = { create: jest.fn().mockReturnValueOnce({ id: 1 }) };
const example = new Example(mockApplicationModel);
const actual = await example.createApp(mockAppDto);
expect(actual).toEqual(1);
expect(mockApplicationModel.create).toBeCalledWith({ email: '123#mock.com', accessToken: 'mock id' });
});
});
test result:
PASS examples/67898249/Example.test.ts (9.134 s)
67898249
✓ should pass (4 ms)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
Example.ts | 100 | 100 | 100 | 100 |
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.1 s

Representing chained methods and members Typescript through Mocha tests

I am testing a node.js controller file using mocha and chai and i'm unable to mock out the response object in my test
TestController.ts
export class TestController {
static async getTest(req:any, res:any, next:object) {
console.log("Test");
//some code here
res.status(200).json(result.rows);
}
and this works perfectly fine when I call the API, returns the right response etc. But when I try to test this Controller, here is what I have for my test file
Test.ts
it('Get Test method', async function () {
let req = {params: {testid: 12345}};
let res:any = {
status: function() { }
};
res.json = '';
let result = await TestController.getTest(req, res, Object);
});
I am not sure how to represent the response object here. If I just declare the variable res in the following way
let res:any;
I see the following error in my test
TypeError: Cannot read property 'json' of undefined
I am not sure how my response data structure res should be for making this test work.
You should use sinon.stub().returnsThis() to mock the this context, it allows you to call chain methods.
E.g.
controller.ts:
export class TestController {
static async getTest(req: any, res: any, next: object) {
console.log('Test');
const result = { rows: [] };
res.status(200).json(result.rows);
}
}
controller.test.ts:
import { TestController } from './controller';
import sinon from 'sinon';
describe('61645232', () => {
it('should pass', async () => {
const req = { params: { testid: 12345 } };
const res = {
status: sinon.stub().returnsThis(),
json: sinon.stub(),
};
const next = sinon.stub();
await TestController.getTest(req, res, next);
sinon.assert.calledWithExactly(res.status, 200);
sinon.assert.calledWithExactly(res.json, []);
});
});
unit test results with 100% coverage:
61645232
Test
✓ should pass
1 passing (14ms)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
controller.ts | 100 | 100 | 100 | 100 |
---------------|---------|----------|---------|---------|-------------------

Using Jest.fn() to see if s3.upload function was called...what am I doing wrong?

I am a bit new to testing and I have been stuck on this issue for quite some time. So I am trying to test a s3.upload() function to see if it called, not to see if it actually uploads the object. The only constraint is that I cannot use any npm packages to mock out the functionality of the s3 bucket.
I was trying to follow this tutorial (How to mock a function inside another function (which I am testing) using sinon?) that uses sinon as a stub, but instead use jest instead. Any help or guidance with issue is appreciated.
// function.js
const uploadToS3 = (params) => {
const response = s3.upload(params).promise();
return response;
}
// functions.test.js
describe("Lambda Handler Function", () => {
test('To test to see if the uploadToS3 function was called', () => {
const sampleParam = {
Bucket: 'BucketName',
Key: 'BucketKey.zip',
Body: 'SGVsbG8sIFdvcmxk'
}
expect(uploadToS3(sampleParam).response).toBeCalled()
})
})
You can use jest.mock(moduleName, factory, options) to mock aws-sdk.
E.g.
function.js:
import AWS from 'aws-sdk';
const s3 = new AWS.S3();
const uploadToS3 = async (params) => {
const response = await s3.upload(params).promise();
return response;
};
export { uploadToS3 };
function.test.js:
import { uploadToS3 } from './function';
import AWSMock from 'aws-sdk';
jest.mock('aws-sdk', () => {
const mS3 = { upload: jest.fn().mockReturnThis(), promise: jest.fn() };
return { S3: jest.fn(() => mS3) };
});
describe('60970919', () => {
it('should pass', async () => {
const mS3 = new AWSMock.S3();
const mResponse = { Bucket: 'xxx' };
mS3.upload({}).promise.mockResolvedValueOnce(mResponse);
const actual = await uploadToS3({});
expect(actual).toEqual(mResponse);
expect(mS3.upload).toBeCalledWith({});
expect(mS3.upload().promise).toBeCalled();
});
});
unit test results with 100% coverage:
PASS stackoverflow/60970919/function.test.js (13.818s)
60970919
✓ should pass (9ms)
-------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
function.js | 100 | 100 | 100 | 100 |
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 15.486s
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/60970919

Mocking a node module in a jest test

I have a Jest test that I am writing for a function which makes an API call. If the API call returns a 403, a function from a node module should be called. I am trying to test this using a mock jest function, but I cannot get the test to use the mocked version of the module I am making.
file.spec.js
import file from './file'
const mockedNodeModule = jest.genMockFromModule('nodeModule')
mockedNodeModule.namedExport = { logout: jest.fn() }
it('call returns a 403', async () => {
await file.apiCall('brand', 'entityType', 'name')
expect(mockedNodeModule.namedExport.logout).toHaveBeenCalled()
})
file.js
import { namedExport } from './nodeModule';
import api from './api';
const apiCall = () => {
return api.makeCall().then(
() => {},
(error) => {
if (error.status === 403) {
namedExport.logout();
}
},
);
};
export default { apiCall };
The test always fails when I check whether mockedNodeModule.namedExport.logout has been called. When I put a breakpoint on the line that it is called, it seems that the mocked version is not being used when the test is running (i.e. it is still using the module from my node_modules). I have also tried using jest.mock() as well, but the result is the same. Is there something wrong in the way that I am setting up the test? Can jest not mock node modules in cases like this?
jest.mock(moduleName, factory, options) should work.
E.g.
file.js:
import { namedExport } from './nodeModule';
import api from './api';
const apiCall = () => {
return api.makeCall().then(
() => {},
(error) => {
if (error.status === 403) {
namedExport.logout();
}
},
);
};
export default { apiCall };
api.js:
function makeCall() {}
export default { makeCall };
nodeModule.js:
export const namedExport = {
logout() {
console.log('real implementation');
},
};
file.test.js:
import file from './file';
import api from './api';
import { namedExport } from './nodeModule';
jest.mock('./nodeModule', () => {
const mNamedExport = {
logout: jest.fn(),
};
return { namedExport: mNamedExport };
});
jest.mock('./api', () => {
return { makeCall: jest.fn() };
});
describe('59831697', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('should handle error if http status equal 403', async () => {
const mError = { status: 403 };
api.makeCall.mockRejectedValueOnce(mError);
await file.apiCall();
expect(namedExport.logout).toHaveBeenCalledTimes(1);
});
});
Unit test results with coverage report:
PASS src/stackoverflow/59831697/file.test.js (13.506s)
59831697
✓ should handle error if http status equal 403 (7ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 50 | 66.67 | 100 | |
file.js | 100 | 50 | 66.67 | 100 | 8 |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 15.448s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59831697

Sinon stub function parameter

I have an express app with a router I would like to test with Sinon. I'm not successful in mocking the response parameter that is passed into the request handler and would like some help.
export const pingHandler = (request, response, next) => {
response.status(200).send('Hello world');
}
This is my current test setup using Mocha, Sinon, Chai & sinon-chai. fakeRes.status was never called as expected.
describe("pingHandler", () => {
it("should return 200", async () => {
const fakeResponse = {
status: sinon.fake(() => ({
send: sinon.spy()
}))
};
pingHandler({}, fakeResponse, {});
expect(fakeResponse.status).to.have.been.called;
// => expected fake to have been called at least once, but it was never called
});
});
Here is the unit test solution:
index.ts:
export const pingHandler = (request, response, next) => {
response.status(200).send('Hello world');
}
index.spec.ts:
import { pingHandler } from "./";
import sinon from "sinon";
describe("pingHandler", () => {
it("should return 200", () => {
const mRes = {
status: sinon.stub().returnsThis(),
send: sinon.stub(),
};
pingHandler({}, mRes, {});
sinon.assert.calledWith(mRes.status, 200);
sinon.assert.calledWith(mRes.send, "Hello world");
});
});
Unit test result with 100% coverage:
pingHandler
✓ should return 200
1 passing (8ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.spec.ts | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|-------------------|

Categories

Resources