Override fs functions - node.js

I am doing some E2E tests using Cypress.
Since it doesnt support node functions such as those from fs, I have mocked them as below.
In my test file:
window.Cypress.fs = require('fs')
window.Cypress.fs.existsSync = () => { return true // custom return }
window.Cypress.fs.lstatSync = () => { // custom return }
But now I am getting some error:
fs.lstatSync(...).isFile is not a function
How can I override/mock/stub isFile()?
I tried doing:
window.Cypress.fs.lstatSync.isFile = () => { return true }
//and
window.Cypress.fs.lstatSync().isFile = () => { return true }
But it doesn't work.
Here is my source code (not the mock):
return fs.lstatSync(filePath).isFile()
Any thoughts??

Since you execute lstatSync() and then use its results, you need to write:
window.Cypress.fs.lstatSync = () => {
return {
isFile() { return true }
}
}

You'll need to mock the fs.Stats class and, at a minimum, its .isFile() method, to do what you want. fs.lstatSync returns an instance of fs.Stats.

Related

Jest - mock function inside another module function

I'm trying to mock the return value (or implementation) of the functions inside another module's function with Jest. I need to test different scenarios (function throws error, returns null, returns an object, etc...)
That module (userService) returns a function that returns an object with that functions:
userService.js (I want to mock the return value of findUser & createUser)
...
function userService(userModel) {
async function findUser(userQuery) {
...
return foundUser;
}
async function createUser(user) {
...
return createdUser;
}
return { findUser, createUser };
}
module.exports = userService;
And I'm testing authStravaController, which uses that service functions:
authStravaController
...
const authStravaServiceRaw = require('../../services/authStravaService');
const userServiceRaw = require('../../services/userService');
const bikeServiceRaw = require('../../services/bikeService');
...
function authStravaController(userModel, bikeModel) {
const { findUser, createUser } = userServiceRaw(userModel); <-- WANT TO MOCK THAT FUNCTIONS
async function authStrava({ body: { authCode } }, res) {
...
try {
...
const findUserQuery = {
stravaUserId: stravaBasicUser.stravaUserId,
};
authUser = await findUser(findUserQuery); <-- MOCK THIS FUNCTION RETURN MULTIPLE TIMES
if (!authUser) {
resStatus = CREATED;
createdUser = await createUser(stravaBasicUser); <-- SAME
...
createdUser.bikes = createdBikes.map((bike) => bike._id);
createdUser.save();
authUser = { createdUser, createdBikes };
}
return handleResponseSuccess(res, resStatus, authUser);
} catch (authStravaError) {
return handleResponseError(res, authStravaError);
}
}
return { authStrava };
}
module.exports = authStravaController;
At the moment I've been able to mock the function return value just 1 time, and I can't find a way to rewrite it, so now I can only test 1 scenario
This code at the top of the file let me test 1 scenario
jest.mock('../../services/userService', () => () => ({
findUser: jest.fn().mockReturnValue(1),
createUser: jest.fn().mockReturnValue({ username: 'userName', save: jest.fn() }),
}));
I've tried to mock it in multiple ways and can't get it to work, how could I do it to test different return values:
findUser: jest.fn().mockReturnValue(1),
findUser: jest.fn().mockReturnValue(undefined),
findUser: jest.fn().mockReturnValue({user:'username'}),
etc...
Thanks!
I fixed it importing all the services outside the controller function, at the top of the file.
This way I can mock the returnValue of any function.

mock a toPromise function in jest - got .toPromise is not a function

I have an httpService from nestjs/common
and I am using like the following:
const response = await this.httpService.post(`${this.api}/${action}`, data).toPromise();
and in my jest spec file ( unit testing) . i am trying to mock this service
httpServiceMock = {
post: jest.fn()
};
it('should start', async () => {
const serviceResult = await service.start(data);
});
and I have got this error :
TypeError: this.httpService.post(...).toPromise is not a function
I am also trying to add a promise result like :
const promise = Promise.resolve('result');
httpServiceMock.post.mockResolvedValue(promise);
tried also :
it('should start', async () => {
const mockObservable = Promise.resolve({
toPromise: () => {
console.log('toPromise called');
}
})
httpServiceMock.post.mockImplementation(() => mockObservable);
const serviceResult = await service.start();
});
My question is how can I mock the promise and return a response or exception
The return value httpService.post needs to return an Observable<AxiosResponse<T>> which includes a property toPromise, which is a function. Your mock returns a resolved promise, whereas it needs to return a fake Observable.
The Observable is returned immediately, so the post implementation can just return a raw value, but the toPromise needs to return a promise.
Return the correct shaped object to get rid of this error:
const mockObservable = {
toPromise: () => Promise.resolve('result')
}
httpServiceMock.post.mockImplementation(() => mockObservable);
I had a similar problem that could not be solved by accepted answer. So I bring here another solution just in case it could help someone else.
If you have jasmine, just use jasmine.createSpyObj(). If not, here is what I needed to do :
First, I implemented a jasmine.createSpyObj() equivalent (based on this answer with little modifications) :
export class TestUtilsService {
static createSpyObj (baseName:string, methodNames:string[]): SpyObject {
let obj: any = {};
for (let i = 0; i < methodNames.length; i++) {
obj[methodNames[i]] = jest.fn();
}
return {[baseName]:()=>obj};
};
}
export class SpyObject {
[key: string]: ()=>{[key:string]:jest.Mock} ;
}
Then I used it in my unit test :
const spyHttpClient: SpyObject = TestUtilsService.createSpyObj('get',['toPromise']);
Add it in test module providers :
{provide: HttpClient, useValue: spyHttpClient}
Finally, mock the toPromise implementation in order to return a mocked response :
const mockedResponse = {...};
spyHttpClient.get().toPromise.mockImplementationOnce(()=>Promise.resolve(mockedResponse));
await service.myRealMethodThatCallsHttpClient();
expect(service.someUpdatedProp).toBeTruthy();
Please notice parenthesis after method get.
"A Jar of Clays" solution didn't work for me (I got mockImplementation is not a function), but this worked:
const mockPromise = {
toPromise: () => Promise.resolve(ical)
}
mockHttpService.get = jest.fn( () => {return mockPromise});

testing an actual returning value on javascript using jest

I have the following js function:
const modelUtils = {
modelingObj(obj, stringVal = ‘RE’) {
let newObj;
//my logic for setting value of newObj
return newObj;
};
export default modelUtils;
I want to test and see that based on a specific params I get a particular result, the issue is I’m always returning back an empty object.
Test.js
import modelUtils from '../modelUtils';
jest.unmock('../modelUtils');
describe(' testing modelUtils', () => {
let test;
const mockData = {
myProperty: [],
};
describe('testing modelingObj function', () => {
it('For my first test’, () => {
test = modelUtils.mockData, ‘TR’);
expect(test).toEqual({ myProperty: [] });
});
});
});

sinon.spy in my Node.JS project when testing an AWS service not working as expected

in my Node.JS project (a backend for an Angular 5 project) I have created a service that deals with the AWS Authentication... I have called this awsAuthenticationService. All works well but I now need to test it. In my awsAuthenticationService.js I have the following method that has some minor logic and then calls a method provided by the "cognitoIdentityServiceProvider". Here is a snippet of my code (I really have reduced this)
constructor() {
this._cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider(this.cognitoConfig);
}
toggleUserAccess(userName, type) {
const params = {
Username: userName,
UserPoolId: this.cognitoConfig.userPoolId
};
if (type === null) {
return this._cognitoIdentityServiceProvider.adminEnableUser(params).promise();
}
return this._cognitoIdentityServiceProvider.adminDisableUser(params).promise();
}
As you can see from the toggleUserAccess we pass a few parameters, determine what they are then call the appropriate method. I wish to test this by having a unit test that will call the authenticationService.toggleUserAccess, pass some params and spy on the authenticationService._cognitoIdentityServiceProvider methods to see if they were called. I set it up so...
let authenticationService = require('./awsAuthenticationService');
describe('toggleUserAccess', () => {
beforeEach(() => {
authenticationService._cognitoIdentityServiceProvider = {
adminDisableUser(params) {
return {
promise() {
return Promise.resolve(params);
}
};
}
};
authenticationService._cognitoIdentityServiceProvider = {
adminEnableUser(params) {
return {
promise() {
return Promise.resolve(params);
}
};
}
};
});
it('should call adminEnableUser if the type is null', () => {
authenticationService.toggleUserAccess('TheUser', null);
const spyCognito = sinon.spy(authenticationService._cognitoIdentityServiceProvider, 'adminEnableUser');
expect(spyCognito.calledOnce).to.equal(true);
});
it('should call adminDisableUser if the type is null', () => {
authenticationService.toggleUserAccess('TheUser', '0001');
const spyCognito = sinon.spy(authenticationService._cognitoIdentityServiceProvider, 'adminDisableUser');
expect(spyCognito.calledOnce).to.equal(true);
});
});
My tests aren't passing and I think I have set up my sinon.spys incorrectly - can anyone see what I am doing wrong or give advice please
To stub class of AWS.CognitoIdentityServiceProvider, need to stub with its prototype keyword.
// add require statement for your AWS class
const spyCognito = sinon.spy(AWS.CognitoIdentityServiceProvider.prototype, 'adminDisableUser');
expect(spyCognito.calledOnce).to.equal(true);
Hope it helps

Is it possible to mock local functions using Jest

I have a file (file.js) consisting of 3 functions in the same file:
file.js:
const fn1 = (number) => {
return number + 1;
}
export const fn2 = (value) => {
return value;
}
export const fn3 = (number) => {
return fn1(number);
}
export const fn4 = (number) => {
return fn2(number);
}
Is it possible to mock out these functions periodically using JEST? What I hope to achieve is something along these lines:
file.test.js:
import { fn2, fn3, fn4 } from 'file.js';
describe('fn2', () => {
test('normal test.' => {
expect(fn2(1)).toBe(1);
})
});
describe('fn3', () => {
test('mock fn1 for this test.' => {
mock fn1 = () => { return 1 };
expect(fn3(2)).toBe(1);
})
});
describe('fn4', () => {
test('mock fn2 for this test.' => {
mock fn2 = () => { return 1 };
expect(fn4(2)).toBe(1);
})
});
It is not possible through the way how JS modules work. Only exported functions are visible to the outside, all other stuff is only visible in the scope of the module, so there is no way to mock it. Also there is no need to mock this function as you only want to test the public API.
The only way to test the function itself and mock it for this module is to put it into an own module, which makes sense if it is some really complicated function where you need good test coverage and it is to complicated to get this when its in another module.

Resources