React. how to mock api call NOT IN TESTS - javascript

E.g. I have a problem when some endpoints are down or causing errors, but I still need to develop.
I have something like UserService.getUsers I am aware of mocking functions in jest and so on, but I have no idea how I'd better get fake data which I can specify myself.
I thought about a HOC, which redefines functions I need to mock like
UserService.getUsers=Promise.resolve({});
But I don't think this is the best way to do this
NOTE: That's not related to testing stuff

If you're using Webpack, you could use the resolve property of the Webpack configuration to alias your imports to some local mocked version.
https://webpack.js.org/configuration/resolve/
For example, if you had some import like this:
import UserService from 'some-package-or-path';
const myData = UserService.getUsers();
You can alias some-package-or-path to a local file:
// webpack.config.js
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
'some-package-or-path': path.resolve(__dirname, 'src/mocks/userServiceMock'),
},
},
};
// userServiceMock index.js
const mock = {
getUserData: () => {
return {
mockedDataProperties: 'whatever'
}
}
};
export default mock;
Obviously your implementation will differ a bit but that's the gist of it.

Related

Jest Typescript class implementation - "... is not a function"

New to Jest so I'm wanting to understand an issue I'm having a bit better. I'm trying to test an implementation of a class in Jest but it's complaining that my function "is not a function"
Typescript Service:
export class TestService {
constructor() { }
getAllData = async (): Promise<any> => {
return { id: '1', name: 'test' }
}
}
Test
import { TestService } from '../TestService';
describe('TestService', async () => {
const service = new TestService();
const res = await service.getAllData();
....
}
jest.config.ts
import type {Config} from '#jest/types';
const config: Config.InitialOptions = {
roots:['<rootDir>'],
testMatch: [
'**/__tests__/**/*.+(ts|tsx|js)',
'**/?(*.)+(spec|test).+(ts|tsx|js)'
],
testPathIgnorePatterns: ['dist', 'node_modules'],
transform: {"\\.(ts|tsx)$": "ts-jest"},
verbose: true,
preset: 'ts-jest',
testEnvironment: 'node',
collectCoverage: true,
automock: true
};
export default config;
When I run the tests, Jest is throwing an error that says "service.getAllData is not a function". Everything I could find online points me to mocks but I wouldn't think I would want to mock this as I want to test the actual implementation of the class; I assume I'd want to mock any external functions within getAllData().
I have a controller that is able to call this function with no problems so I'm wondering if either 1) there's some other way this must be called or 2) Jest essentially requires mocks of some kind.
Please let me know if you have any insight
Thanks!
automock is a bad practice and should be preferably disabled. In case a module needs to be automatically mocked, this can be done explicitly with jest.mock. Manual mocks are preferable most times because they result in explicitly specified implementations that should be additionally provided to auto-mocks, too.
Jest auto-mocking is undocumented, it results in poorly understood magic that may not meet the expectations of a developer and may change without notice in next Jest versions. Class auto-mocking is briefly described in the guide. getAllData is instance method that is created inside a constructor. Jest auto-mocking relies on runtime contents of a module and checks static and prototype members, there's no way how it could process a constructor.
In order to be detected by Jest auto-mocking, getAllData should be prototype method, this is also suggested by common sense because there are no reasons for it to be an arrow:
export class TestService {
getAllData(): Promise<any> {
return { id: '1', name: 'test' }
}
}
Auto-mocking doesn't result in a correct mock because the method is stubbed it doesn't return a promise. The problem could be determined at earlier point because auto-mocks require an implementation to be specified, this wasn't done in the OP:
const service = new TestService();
service.getAllData.mockResolvedValueOnce(...);
...
For prototype methods this can be done before an instance is available:
TestService.prototype.getAllData.mockResolvedValueOnce(...);
const service = new TestService();
...

How to mock an axios configuration module?

I have a module which configures axios:
// config/axiosConfig.js
import axios from 'axios';
const instance = axios.create({
baseURL: 'http://localhost:8080/api/v1'
});
export default instance;
And a module that uses this to make api calls:
// store/actions.ts
import axiosInstance from 'config/axiosConfig';
export const fetchUsers = () => (dispatch: ThunkDispatch<{}, {}, AnyAction>) => {
dispatch(loading(true));
return axiosInstance.get('/users')
.then(res => {
dispatch(loading(false));
dispatch(fetched(res.data));
})
.catch(err => dispatch(error(true)));
}
...
I want to mock the axios config file to test my api file. I've tried many many ways but nothing works. I thought it would be as simple as
// store/actions.test.ts
import axiosInstance from 'config/axiosConfig';
jest.mock('config/axiosConfig');
axiosConfig.get.mockResolvedValue({users: mockUserList});
...
But I guess that's not how it works.
Edit: The approach in my question works when I put axiosConfig.get.mockResolvedValue({users: mockUserList}); inside of the test, not right under the mock call.
Try this out (Put this at the top of the file or at the top inside beforeAll or beforeEach depending on what you prefer):
jest.mock('config/axiosConfig', () => ({
async get(urlPath) {
return {
users: mockUserList,
};
},
}));
This is a simple mock using a factory function. To use a mock everywhere, jest provides a better way to avoid repeating yourself. You create a __mocks__ directory and inside that, you can create your module and then override many of the builtins. Then, you can get away with just the following code.
// file.test.ts
jest.mock('fs')
// Rest of your testing code below
Take a look at the official docs to learn more about this.
If this doesn't work, then the module resolution setup in jest.config.js and tsconfig.js might be different.

Re-including a module on-the-fly

I am currently working on technical debt identified by SonarQube for a Node.js application. My application allows on-the-fly switching between a live and mock datasource. To achieve this I destroy the previous "require" from cache and re-require it. When running SonarQube it does not like "require" statements. It does suggest "import" statements. However that may not be suitable in this case.
Simplified version of existing code:
var config = require('../config');
var polService = require(config.polService);
var root = require('../root');
function doingStuff(liveOrMock) {
setEnvironment(liveOrMock);
delete require.cache[require.resolve(root.path + ‘/config’)];
config = require('../config');
polService = require(config.polService);
}
The setEnvironment function sets process.env.NODE_ENV = liveOrMock, which is used in config.js. We export the config module using module.exports = localOptions[process.env.NODE_ENV]; This code picks a single key-pair from a JSON. The value that comes back is used to choose which module is being used for a restService.
Being able to change what module is being used is for polService is the purpose of the code.
Change your config module to export a function, and then call this function whenever you need to change environment.
In order to make polService a dynamic module, you can use dynamic import(). import() is not supported natively, but you can use this Babel plugin (it works with webpack) to transpile it.
config.js:
export default () => {
// ...
return localOptions[process.env.NODE_ENV];
}
Main module:
import getConfig from '../config';
let config = getConfig();
function doingStuff(liveOrMock) {
setEnvironment(liveOrMock);
config = getConfig();
return import(config.polService).then(result => {
polService = result;
});
}
Keep in mind that now the doingStuff function is asynchronous (i.e. returns a promise), so you can't just call it and access polService immediately. You have to wait for it by either using the then() method, or using await in an async function.
If you have a limited number of polService modules, it might be a better option to import all of them beforehand, and in the doingStuff function just switch which one the polService variable refers to.
import getConfig from '../config';
import polService1 from '../polService1';
import polService2 from '../polService2';
import polService3 from '../polService3';
const polServices = { polService1, polService2, polService3 };
let config = getConfig();
let polService = polService1;
function doingStuff(liveOrMock) {
setEnvironment(liveOrMock);
config = getConfig();
polService = polServices[config.polService];
}

How to mock dependencies for unit tests with ES6 Modules

I'm trying to fiddle with Ecmascript 6 modules using webpack + traceur to transpile to ES5 CommonJS, but I'm having trouble successfully unit testing them.
I tried using Jest + traceur preprocessor, but the automocking and dependency names seem to get screwy, plus I can't seem to get sourceMaps to work with Jest and node-inspector debugging.
Is there a better framework to unit test ES6 modules?
I've started employing the import * as obj style within my tests, which imports all exports from a module as properties of an object which can then be mocked. I find this to be a lot cleaner than using something like rewire or proxyquire or any similar technique.
I can't speak for traceur which was the framework used in the question, but I've found this to work with my setup of Karma, Jasmine, and Babel, and I'm posting it here as this seems to be the most popular question of this type.
I've used this strategy most often when needing to mock Redux actions. Here's a short example:
import * as exports from 'module-you-want-to-mock';
import SystemUnderTest from 'module-that-uses-above-module';
describe('your module', () => {
beforeEach(() => {
spyOn(exports, 'someNamedExport'); // mock a named export
spyOn(exports, 'default'); // mock the default export
});
// ... now the above functions are mocked
});
If you are using Webpack another option that has a little more flexibility than rewire is inject-loader.
For example, in a test that is bundled with Webpack:
describe('when an alert is dismissed', () => {
// Override Alert as we need to mock dependencies for these tests
let Alert, mockPubSub
beforeEach(() => {
mockPubSub = {}
Alert = require('inject!./alert')({
'pubsub-js': mockPubSub
}).Alert
})
it('should publish \'app.clearalerts\'', () => {
mockPubSub.publish = jasmine.createSpy()
[...]
expect(mockPubSub.publish).toHaveBeenCalled()
})
})
inject-loader, in a similar manner to proxyquire at least allows one to inject dependencies before importing whereas in rewire you must import first and then rewire which makes mocking some components (e.g. those that have some initialization) impossible.
Hi you could use proxyquire:
import assert from 'assert';
import sinon from 'sinon';
import Proxyquire from 'proxyquire';
let proxyquire = Proxyquire.noCallThru(),
pathModelLoader = './model_loader';
describe('ModelLoader module.', () => {
it('Should load all models.', () => {
let fs, modelLoader, ModelLoader, spy, path;
fs = {
readdirSync(path) {
return ['user.js'];
}
};
path = {
parse(data) {
return {name: 'user'};
}
};
ModelLoader = proxyquire(pathModelLoader, {'fs': fs, 'path': path});
modelLoader = new ModelLoader.default();
spy = sinon.spy(modelLoader, 'loadModels');
modelLoader.loadModels();
assert(spy.called);
});
});
I actually got this to work by dropping Jest and going with Karma + Jasmine + Webpack and using https://github.com/jhnns/rewire to mock dependencies
Proxyquire will help you, but it not gonna to work with modern webpack+ES6 modules, ie "aliases".
import fs from 'fs';
import reducers from 'core/reducers';
...
proxyquire('../module1', {
'fs': mockFs, // this gonna work
'core/reducers': mockReducers // what about this?
});
that will not work.
As long you can mock fs - you cannot mock reducers.
You have to specify real name of dependency, after any webpack or babel transformation. Normally - name relative to module1 location. May be '../../../shared/core/reducers'. May be not.
There is drop in solutions - https://github.com/theKashey/proxyquire-webpack-alias (stable, based on fork of proxyquire) or https://github.com/theKashey/resolveQuire (less stable, can be run upon original proxyquire)
Both of them works as well, and will mock any ES6 module(they are dam good) in a proxyquire way(it is a good way)

How to unit test a Node.js module that requires other modules and how to mock the global require function?

This is a trivial example that illustrates the crux of my problem:
var innerLib = require('./path/to/innerLib');
function underTest() {
return innerLib.doComplexStuff();
}
module.exports = underTest;
I am trying to write a unit test for this code. How can I mock out the requirement for the innerLib without mocking out the require function entirely?
So this is me trying to mock out the global require and finding out that it won’t work even to do that:
var path = require('path'),
vm = require('vm'),
fs = require('fs'),
indexPath = path.join(__dirname, './underTest');
var globalRequire = require;
require = function(name) {
console.log('require: ' + name);
switch(name) {
case 'connect':
case indexPath:
return globalRequire(name);
break;
}
};
The problem is that the require function inside the underTest.js file has actually not been mocked out. It still points to the global require function. So it seems that I can only mock out the require function within the same file I’m doing the mocking in. If I use the global require to include anything, even after I’ve overridden the local copy, the files being required will still have the global require reference.
You can now!
I published proxyquire which will take care of overriding the global require inside your module while you are testing it.
This means you need no changes to your code in order to inject mocks for required modules.
Proxyquire has a very simple api which allows resolving the module you are trying to test and pass along mocks/stubs for its required modules in one simple step.
#Raynos is right that traditionally you had to resort to not very ideal solutions in order to achieve that or do bottom-up development instead
Which is the main reason why I created proxyquire - to allow top-down test driven development without any hassle.
Have a look at the documentation and the examples in order to gauge if it will fit your needs.
A better option in this case is to mock methods of the module that gets returned.
For better or worse, most node.js modules are singletons; two pieces of code that require() the same module get the same reference to that module.
You can leverage this and use something like sinon to mock out items that are required. mocha test follows:
// in your testfile
var innerLib = require('./path/to/innerLib');
var underTest = require('./path/to/underTest');
var sinon = require('sinon');
describe("underTest", function() {
it("does something", function() {
sinon.stub(innerLib, 'toCrazyCrap').callsFake(function() {
// whatever you would like innerLib.toCrazyCrap to do under test
});
underTest();
sinon.assert.calledOnce(innerLib.toCrazyCrap); // sinon assertion
innerLib.toCrazyCrap.restore(); // restore original functionality
});
});
Sinon has good integration with chai for making assertions, and I wrote a module to integrate sinon with mocha to allow for easier spy/stub cleanup (to avoid test pollution.)
Note that underTest cannot be mocked in the same way, as underTest returns only a function.
Another option is to use Jest mocks. Follow up on their page
I use mock-require. Make sure you define your mocks before you require the module to be tested.
Simple code to mock modules for the curious
Notice the parts where you manipulate the require.cache and note require.resolve method as this is the secret sauce.
class MockModules {
constructor() {
this._resolvedPaths = {}
}
add({ path, mock }) {
const resolvedPath = require.resolve(path)
this._resolvedPaths[resolvedPath] = true
require.cache[resolvedPath] = {
id: resolvedPath,
file: resolvedPath,
loaded: true,
exports: mock
}
}
clear(path) {
const resolvedPath = require.resolve(path)
delete this._resolvedPaths[resolvedPath]
delete require.cache[resolvedPath]
}
clearAll() {
Object.keys(this._resolvedPaths).forEach(resolvedPath =>
delete require.cache[resolvedPath]
)
this._resolvedPaths = {}
}
}
Use like:
describe('#someModuleUsingTheThing', () => {
const mockModules = new MockModules()
beforeAll(() => {
mockModules.add({
// use the same require path as you normally would
path: '../theThing',
// mock return an object with "theThingMethod"
mock: {
theThingMethod: () => true
}
})
})
afterAll(() => {
mockModules.clearAll()
})
it('should do the thing', async () => {
const someModuleUsingTheThing = require('./someModuleUsingTheThing')
expect(someModuleUsingTheThing.theThingMethod()).to.equal(true)
})
})
BUT... jest has this functionality built in and I recommend that testing framework over rolling your own for testing purposes.
Mocking require feels like a nasty hack to me. I would personally try to avoid it and refactor the code to make it more testable.
There are various approaches to handle dependencies.
1) pass dependencies as arguments
function underTest(innerLib) {
return innerLib.doComplexStuff();
}
This will make the code universally testable. The downside is that you need to pass dependencies around, which can make the code look more complicated.
2) implement the module as a class, then use class methods/ properties to obtain dependencies
(This is a contrived example, where class usage is not reasonable, but it conveys the idea)
(ES6 example)
const innerLib = require('./path/to/innerLib')
class underTestClass {
getInnerLib () {
return innerLib
}
underTestMethod () {
return this.getInnerLib().doComplexStuff()
}
}
Now you can easily stub getInnerLib method to test your code.
The code becomes more verbose, but also easier to test.
If you've ever used jest, then you're probably familiar with jest's mock feature.
Using "jest.mock(...)" you can simply specify the string that would occur in a require-statement in your code somewhere and whenever a module is required using that string a mock-object would be returned instead.
For example
jest.mock("firebase-admin", () => {
const a = require("mocked-version-of-firebase-admin");
a.someAdditionalMockedMethod = () => {}
return a;
})
would completely replace all imports/requires of "firebase-admin" with the object you returned from that "factory"-function.
Well, you can do that when using jest because jest creates a runtime around every module it runs and injects a "hooked" version of require into the module, but you wouldn't be able to do this without jest.
I have tried to achieve this with mock-require but for me it didn't work for nested levels in my source. Have a look at the following issue on github: mock-require not always called with Mocha.
To address this I have created two npm-modules you can use to achieve what you want.
You need one babel-plugin and a module mocker.
babel-plugin-mock-require
jestlike-mock
In your .babelrc use the babel-plugin-mock-require plugin with following options:
...
"plugins": [
["babel-plugin-mock-require", { "moduleMocker": "jestlike-mock" }],
...
]
...
and in your test file use the jestlike-mock module like so:
import {jestMocker} from "jestlike-mock";
...
jestMocker.mock("firebase-admin", () => {
const firebase = new (require("firebase-mock").MockFirebaseSdk)();
...
return firebase;
});
...
The jestlike-mock module is still very rudimental and does not have a lot of documentation but there's not much code either. I appreciate any PRs for a more complete feature set. The goal would be to recreate the whole "jest.mock" feature.
In order to see how jest implements that one can look up the code in the "jest-runtime" package. See https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/index.js#L734 for example, here they generate an "automock" of a module.
Hope that helps ;)
You can't. You have to build up your unit test suite so that the lowest modules are tested first and that the higher level modules that require modules are tested afterwards.
You also have to assume that any 3rd party code and node.js itself is well tested.
I presume you'll see mocking frameworks arrive in the near future that overwrite global.require
If you really must inject a mock you can change your code to expose modular scope.
// underTest.js
var innerLib = require('./path/to/innerLib');
function underTest() {
return innerLib.toCrazyCrap();
}
module.exports = underTest;
module.exports.__module = module;
// test.js
function test() {
var underTest = require("underTest");
underTest.__module.innerLib = {
toCrazyCrap: function() { return true; }
};
assert.ok(underTest());
}
Be warned this exposes .__module into your API and any code can access modular scope at their own danger.
You can use mockery library:
describe 'UnderTest', ->
before ->
mockery.enable( warnOnUnregistered: false )
mockery.registerMock('./path/to/innerLib', { doComplexStuff: -> 'Complex result' })
#underTest = require('./path/to/underTest')
it 'should compute complex value', ->
expect(#underTest()).to.eq 'Complex result'
I use a simple factory the returns a function that calls a function with all of its dependencies:
/**
* fnFactory
* Returns a function that calls a function with all of its dependencies.
*/
"use strict";
const fnFactory = ({ target, dependencies }) => () => target(...dependencies);
module.exports = fnFactory;
Wanting to test the following function:
/*
* underTest
*/
"use strict";
const underTest = ( innerLib, millions ) => innerLib.doComplexStuff(millions);
module.exports = underTest;
I would setup my test (I use Jest) as follows:
"use strict";
const fnFactory = require("./fnFactory");
const _underTest = require("./underTest");
test("fnFactory can mock a function by returng a function that calls a function with all its dependencies", () => {
const fake = millions => `Didn't do anything with ${millions} million dollars!`;
const underTest = fnFactory({ target: _underTest, dependencies: [{ doComplexStuff: fake }, 10] });
expect(underTest()).toBe("Didn't do anything with 10 million dollars!");
});
See results of test
In production code I would manually inject the callee's dependencies as below:
/**
* main
* Entry point for the real application.
*/
"use strict";
const underTest = require("./underTest");
const innerLib = require("./innerLib");
underTest(innerLib, 10);
I tend to limit the scope of most of the modules that I write to one thing, which reduces the number of dependencies that have to be accounted for when testing and integrating them into the project.
And that's my approach to dealing with dependencies.

Categories