jest manual mock imports are not working - jestjs

For some reason Jest is not picking up my manual mock implementation. The structure is the following. Am I missing something here? It is for sure hoisting the .mock call, I've tested it with the mock call above imports and still no dice.
Appreciate any help.
--
// "#/store/modules/__tests__/data"
import {fetchData} from "#/store/modules/data"
import {fetchByids} from "#/api/fetch";
jest.mock("#/api/fetch");
...
[ fetchByIds is considered the original still ? ]
--
// "#/store/modules/data"
import {fetchByIds} from "#/api/fetch";
...
export const fetchData = (context, payload) => {
fetchByIds(payload.id);
}
--
// "#/api/fetch"
export const fetchByIds = (id) => fetch(`url${id}`).then(response=>response.json())
--
// "#/api/__mocks__/fetch"
export const fetchByIds = jest.fn().mockImplementation(id => Promise.resolve({id}))
--
What's interesting is if I add the following to "#/store/modules/__tests__/data" it picks up the mock implementation. So maybe it's an issue with name mapping?
jest.mock("#/api/fetch", () => ({
fetchByIds: jest.fn().mockImplementation(id => Promise.resolve({id}))
}));

Related

react jest mock useNavigate()

I am trying to mock the useNavigate hook using Jest. I was able to do it at the top level of my test suit (I also have a custom render with BrowserRouter as a wrapper)
const mockedUsedNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...(jest.requireActual('react-router-dom') as any),
useNavigate: () => mockedUsedNavigate,
}));
...
expect(mockedUsedNavigate).toHaveBeenCalledWith('myurl/user-1');
My issue is that I want to have this mock available inside the __mocks__ directory so I can use it in other tests as well instead if having to write it again and again. I wasn't able to do it.
Is it possible?
You should be able create a src.setupTests.js file in your project and declare the mock there.
See Initializing Test Environment
src/setupTests.js
export const navigateMock = jest.fn(); // <-- exported for test assertions
jest.mock('react-router-dom', () => ({
...(jest.requireActual('react-router-dom') as any),
useNavigate: () => navigateMock,
}));
You can then import the exported navigateMock function in test files.

node ts-jest spyOn method does not match overload

I'm trying to use Jest in conjunction with ts-jest to write unit tests for a nodeJS server. I have something set up very similar to below:
impl.ts
export const dependency = () => {}
index.ts
import { dependency } from './impl.ts';
export { dependency };
consumer.ts
import { dependency } from '../impl' <- importing from index.ts
export const consumer = () => {
try {
dependecy();
return true;
} catch (error) {
return false;
}
}
consumer.test.ts
import * as dependencies from '../impl'
import { consumer } from './consumer'
const mockDependency = jest.spyOn(dependencies, 'depenedncy');
describe('function consumer', function () {
beforeEach(function () {
mockDependency.mockReturnValueOnce(false);
});
test('should return true', () => {});
})
This is just toy code, but the actual export / import / test files follow a similar structure. I'm getting typescript errors along these lines:
TS2769: No overload matches this call.
Specifically, that the method being spied on is not part of the overload of the import for dependencies, so I can't stub it out. I am doing literally the same thing in a different test file and it has no issues. Anyone know how to resolve the typing issue?
The issue turned out to be in the typing of the dependency function itself. The return value typing was incorrect and that was what was resulting in the Typescript error. Essentially I had this:
export const dependency: Handler = () => {
return () => {} <- is of type Handler
}
rather than this
export const dependency = (): Handler => {
return () => {} <- is of type Handler
}
Stupid mistake, hope it helps someone else in the future. My take away is that if you have a type error that doesn't make sense make sure you check the typing of all variables involved.

Jest - getting error when mocking FS modules and calling config module

I'm writing unit tests with Jest trying to test a module which uses FS.
The module file:
import fs from 'fs';
import logger from './logger.utils';
export const getNumberOfFiles = async (targetDir: string): Promise<number> => {
// get number of folders
logger.info(`getNumberOfFiles from ${targetDir}/${fileName}`);
const numberOfFiles = await fs.readdirSync(targetDir);
return numberOfFiles.length;
};
Test file
import fs from 'fs';
import { getNumberOfFiles } from '../../src/utils/fs.utils';
jest.mock('fs');
describe('fs.utils', () => {
describe('getNumberOfFiles', () => {
it('Should return number', async () => {
fs.readdirSync = jest.fn();
const readdirSyncMock = fs.readdirSync = jest.fn();
readdirSyncMock.mockResolvedValue([1, 2, 3]);
const result = await getNumberOfFiles('targetDir');
expect(result).toEqual(3);
expect(readdirSyncMock.mock.calls.length).toEqual(1);
});
});
});
When I run the test file, I get the following error:
Config file ..../config/runtime.json cannot be read. Error code is: undefined. Error message is: Cannot read property 'replace' of undefined
1 | const cheggLogger = require('#chegg/logger');
2 | import loggingContext from './loggingContext';
> 3 | import config from 'config';
| ^
4 | import os from 'os';
5 | import constants from '../../config/constants';
6 |
at Config.Object.<anonymous>.util.parseFile (node_modules/config/lib/config.js:789:13)
at Config.Object.<anonymous>.util.loadFileConfigs (node_modules/config/lib/config.js:666:26)
at new Config (node_modules/config/lib/config.js:116:27)
at Object.<anonymous> (node_modules/config/lib/config.js:1459:31)
at Object.<anonymous> (src/utils/logger.utils.ts:3:1)
Content of logger.utils.ts
const internalLogger = require('internalLogger');
import loggingContext from './loggingContext';
import config from 'config';
import os from 'os';
import constants from '../../config/constants';
const logger = internalLogger.createLogger({
level: config.get(constants.LOG_LEVEL)
});
export default logger;
I assume that config is using FS, and once I mock the module, it fails.
How can I resolve this? Please advise
I'm guessing the problem comes from config also using the fs api but you are now mock entire module fs which makes all methods should be mocked before using.
But I have an idea for you by using jest.doMock which you can provide a factory for each test and just mock only method we need. Here is a draft idea:
describe('fs.utils', () => {
describe('getNumberOfFiles', () => {
it('Should return number', async () => {
jest.doMock('fs', () => ({
// Keep other methods still working so `config` or others can use
// so make sure we don't break anything
...jest.requireActual('fs'),
readdirSync: jest.fn(pathUrl => {
// Mock for our test path since `config` also uses this method :(
return pathUrl === 'targetDir' ? Promise.resolve([1, 2, 3]) : jest.requireActual('fs').readdirSync(pathUrl)
})
}));
// One of the thing we should change is to switch `require` here
// to make sure the mock is happened before we actually require the code
// we can also use `import` here but requires us do a bit more thing
// so I keep thing simple by using `require`
const {getNumberOfFiles} = require('../../src/utils/fs.utils');
const result = await getNumberOfFiles('targetDir');
expect(result).toEqual(3);
// you might stop assert this as well
// expect(readdirSyncMock.mock.calls.length).toEqual(1);
});
});
});
Just also want to check, if you created a config file as described here: https://www.npmjs.com/package/config#quick-start

Mocha how to use utils function stackTraceFilter()

i try to use the mocha utils stackTraceFilter() function
but i cannot find an example usage case where someone explains how to use it in ones test. I found the official tests here: link
But how can i implement it in my tests, which somehow look like that:
import { expect } from 'chai'
import 'mocha'
import { main, main2 } from './'
describe.only('index.ts', async () => {
it('should start a job', async () => {
// const R_RUN_MAIN = await main()
await main2()
// TEST
expect(1).to.equal(1) // fails
})
})
In the tests i can see the line
expect(filter(stack.join('\n')), 'to be', stack.slice(0, 3).join('\n'));
But how do i get the Stack for my test?
expect(1).to.equal(1) // fails
or in general, how do i get the stack and initialize the filter function for the whole file when, for example, code from an imported file is already failing and creating a long stack trace?
UPDATE (2018.08.15)
so i got mocha running in a programmatic way:
export {}
import * as MOCHA from 'mocha'
async function run() {
const mocha = new MOCHA({
reporter: 'progress',
reporterOptions: {
verbose: true,
},
})
mocha.addFile(`./src/utils/mocha/index.spec.ts`)
const R = mocha.run((failures) => {
process.on('exit', () => {
process.exit(failures)
})
})
}
run()
I dont know where to add and run the Filter function?
const filter = MOCHA.utils.stackTraceFilter
The stackTraceFilter() function in mocha isn't meant to filter your code, but rather the mocha internals that in theory shouldn't be relevant to your tests. You can view the source code, but to sum it up it just filters out 'mocha' and 'node' lines from the stack, depending on the environment you're in.
I think what you're looking for could be accomplished through the package StackTraceJS, which allows you to grab a stack from anywhere, and do what you want with it. We created a custom reporter for mocha which uses it, and it works quite well.
So, using the example from their site:
StackTrace.get()
.then(function(stack){
// you now have a stack, and can filter as you wish
})
.catch(function(err){});

Cannot mock filesystem in nodejs unit tests

Overview
I have a simple module written in nodejs that uses fs-extra package to test if a file exists. The module throws when the path exists and proceed to next procedure otherwise. Here is the source file:
// - main.js -
import fs from 'fs-extra'
export default async (pathName) => {
// Do not proceed if path already exists.
if (await fs.pathExists(projectPath)) {
throw new Error(chalk.red.bold(`${projectPath} already exists`))
}
// more logic here
}
I want to write a unit test that tests the bellow logic:
If filepath exists, we expect to throw an error
I don't want to mess up with the real filesystem -in case my code contains some nasty bug that could destroy it- so I went to an alternative solution, mocking the filesystem using mock-fs. Here is the spec file:
// - main.js spec file -
import mainFunction from '../main'
import mockfs from 'mock-fs'
describe('test main function', () => {
beforeEach(() => {
mockfs({
home: {
user: {
dummy: {}
}
}
})
})
test('expect to throw', async () => {
await mainFunction('/home/user/dummy')
})
afterEach(() => {
mockfs.restore()
})
})
What's the problem?
Every time I run the test, the main function does not throw. This happens because mockfs fake-filesystem was declared in the spec file, so the fs module in main source file does not know for the mockfs fake-filesystem and checks the real one. By the time that I do not have a folder named /home/user/dummy in my real filesystem the check always fails.
Expected behaviour
mainFunction in spec file should throw
Actual behaviour
mainFunction in spec file DOES NOT throw
Other info
I guess that I can turn this unit test into an integration test. But I do not want to. Is there any fix for this? Do I have to use another packages?
My test suit is Jest 22.3.0.
After some search, I found the appropriate way to unit test the branch. We really do not have to use the mock-fs module. We just have to mock pathExists method of fs-extra module to return one time the value false and one time the value true. Bellow, I post a working version of my spec file:
import mainFunction from '../main'
require('fs-extra').pathExists = jest.fn().mockReturnValueOnce(false).mockReturnValueOnce(true)
describe('test main function', () => {
beforeEach(() => {
jest.clearAllMocks()
})
test('expect to not throw', async () => {
await expect(mainFunction('/dummy/path/does/not/matter')).resolves
})
test('expect to throw', async () => {
await expect(mainFunction('/dummy/path/does/not/matter')).rejects.toBeInstanceOf(Error)
})
})

Resources