How to cleanup jest beforeEach and afterEach in a loop - javascript

I have a loop that inside has beforeEach and it. Whenever I run, I can see that beforeEach and afterEach functions persist in the loop. How can I remove them?
describe('test', () => {
['1', '2', '3'].forEach(each => {
beforeEach(() => {
console.log(`before ${each}`)
})
it('test 1', () => {
console.log(`test1 ${each}`)
})
it('test 2', () => {
console.log(`test1 ${each}`)
})
})
I'm getting on the console:
before 1
test 1
before 1
test 2
before 1
before 2
test 1
before 1
before 2
test 2
before 1
before 2
before 3
test 1
before 1
before 2
before 3
test 2

Related

How to mock a primitive const value using jest and restore the mock?

So suppose I have a file named "config.js":
export const DELAY_SECONDS = 5;
And when doing the tests:
// Ignore the delay when doing the tests.
jest.mock("/path/to/config", () => ({ DELAY_SECONDS: 0 }))
But I also want to test if the original value works:
it('should work with delay', () => {
// Use original value implicitly.
a_function_uses_DELAY_SECONDS()
expect(...).toBe(...)
})
How could I restore that mock? Or is there a better way to implement the mock?
I have tried something below and none of them works:
it('should work with delay', () => {
jest.unmock() // Doesn't work at all, don't even know what does this method do.
// Use original value implicitly.
a_function_uses_DELAY_SECONDS()
expect(...).toBe(...)
})
it('should work with delay', () => {
jest.mock("/path/to/config", () => ({ DELAY_SECONDS: 5 })) // Call the mock again doesn't work
// Use original value implicitly.
a_function_uses_DELAY_SECONDS()
expect(...).toBe(...)
})
it('should work with delay', () => {
const config = require("/path/to/config").default;
config.DELAY_SECONDS = 5; // Won't work, as it is a constant, cannot modify
// Use original value implicitly.
a_function_uses_DELAY_SECONDS()
expect(...).toBe(...)
})
You could use jest.doMock(moduleName, factory, options).
E.g.
config.js:
export const DELAY_SECONDS = 5;
main.js:
import { DELAY_SECONDS } from './config';
function main() {
return DELAY_SECONDS;
}
export { main };
main.test.js:
describe('64473533', () => {
beforeEach(() => {
jest.resetModules();
});
it('should work with delay - original', () => {
const { main } = require('./main');
const actual = main();
expect(actual).toBe(5);
});
it('should work with delay - mocked', () => {
jest.doMock('./config', () => ({ DELAY_SECONDS: 0 }));
const { main } = require('./main');
const actual = main();
expect(actual).toBe(0);
});
});
unit test result:
PASS src/stackoverflow/64473533/main.test.js
64473533
✓ should work with delay - original (445ms)
✓ should work with delay - mocked (2ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
config.js | 100 | 100 | 100 | 100 | |
main.js | 100 | 100 | 100 | 100 | |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.694s

Display test file name in Mocha output

Is there anyway to have mocha display the name of, or group the output by the test file?
Given two test files, ./test/testFoo.js and ./test/testBar.js I'd like to see something like this when running mocha test:
* testFoo:
Doing X
✓ should return A
✓ even with negative input
Doing Y
✓ should return B
✓ should return C when called with Egyptian hieroglyphs
* testBar:
Doing Z
✓ should return D
(This might be an XY problem. If there are other way to group tests in two levels, I'm just as interested. It's just that the files are already there, as a kind of natural first level group.)
I got tired of there being no solution for this every time I went searching for one and built my own reporter:
https://www.npmjs.com/package/mocha-spec-reporter-with-file-names
That page contains the details but here they are repeated:
install it: npm i -D mocha-spec-reporter-with-file-names
set it at your reporter
cli: npx mocha --reporter './node_modules/mocha-spec-reporter-with-file-names'
config:
// .mocharc.js
const SpecReporterWithFileNames = require('mocha-spec-reporter-with-file-names');
module.exports = {
reporter: SpecReporterWithFileNames.pathToThisReporter,
};
Output currently looks like this:
You should be good using Mocha's describe method to logically group your tests. For the output you desire, the structure of your tests would look like:
/test/testFoo.js
describe('testFoo', () => {
describe('Doing X', () => {
it('should return A', () => {
});
it('even with negative input', () => {
});
});
describe('Doing Y', () => {
it('should return B', () => {
});
it('should return C when called with Egyptian hieroglyphs', () => {
});
});
});
/test/testBar.js
describe('testBar', () => {
describe('Doing Z', () => {
it('should return D', () => {
});
});
});

How to overwrite the mocked data for a module in different test suite in Jest

I have a scenario where I have to update the mocked response for a module with different set of values in a different test suite in one of my unit test case written in Jest. Here is my test file looks like :
// test.spec.js
jest.mock('../../Service', () => ({
getState: jest.fn().mockReturnValue({
x: 'x',
y: 'y',
z: 'z'
})
})
describe('Test suite 1 - with same mocked data for Service', () => ({
// expected Service.getState() --> { x: 'x', y: 'y', z: 'z' }
})
describe('Test suite 2 - with different mocked data for Service', () => ({
// expected Service.getState() --> { a: 'a', b: 'b' }
})
How do I update the mock value for the following module with an another set of values within the 2nd test suite as follows ?
jest.mock('../../Service', () => ({
getState: jest.fn().mockReturnValue ({
a: 'a',
b: 'b'
})
})
Is it possible to overwrite the mocked values using beforeEach() method in the second test suite ? Can someone let me the right way to handle this scenario ?
Any help on this would be greatly appreciated.
describe('Test suite 1 - with same mocked data for Service', () => ({
// expected Service.getState() --> { x: 'x', y: 'y', z: 'z' }
jest.mock('../../Service', () => ({
getState: jest.fn().mockReturnValue({
x: 'x',
y: 'y',
z: 'z'
})
})
})
describe('Test suite 2 - with different mocked data for Service', () => ({
// expected Service.getState() --> { a: 'a', b: 'b' }
jest.mock('../../Service', () => ({
getState: jest.fn().mockReturnValue({
a: 'a',
b: 'b',
})
})
})
You have to mock the service separately in every test case. Rather then globally in the describe block.
let suppose you have a test file SomeComponent.jsx which involves mocking the ../../Service dependency then this is what you can do:
import { Service } from "../../Service";
jest.mock("../../Service", ({
getState: jest.fn(),
}));
describe("SomeComponent", () => {
describe('Test suite 1 - with same mocked data for Service', () => {
it('should expect mock response 1', () => {
getState.mockImplementation(() => {
return {
x: 'x',
y: 'y',
z: 'z'
}
})
expect(Service.getState()).toEqual({x: 'x', y: 'y', z: 'z'});
});
});
describe('Test suite 2 - with different mocked data for Service', () => {
it('should expect mock response 2', () => {
getState.mockImplementation(() => {
return {a: 'a', b: 'b'}
})
expect(Service.getState()).toEqual({a: 'a', b: 'b'});
});
});
});
You want to test both objects of getState, so you use mockReturnValueOnce to make the mock function return object1 in the first invocation, and object2 in the second one.
You import the mocked module in your case its import {Service} from "../../Service"; to gain access to the mock function. Then, you call mockImplementation inside the test body in different test suits to setup the right return value.

Execute BeforeEach Hook before Before Hook in Mocha

I want to create a beforeEach Hook that is executed before a before Hook.
Basically I want the following behaviour:
beforeEach(() => {
console.log('beforeEach')
})
describe('tests', () => {
before(() => {
console.log('before')
})
it('test 1', () => {
console.log('it')
})
})
And I get:
before
beforeEach
it
But the output I want is:
beforeEach
before
it
What would be the correct structure to get the desired behaviour?
Workaround
Currently I found a workaround using two nested beforeEach:
beforeEach(() => {
console.log('beforeEach1')
})
describe('tests', () => {
beforeEach(() => {
console.log('beforeEach2')
})
it('test 1', () => {
console.log('it')
})
})
Which output is:
beforeEach1
beforeEach2
it
I am not sure of this (I have not tested it) but from the doc it seems that your root-level beforeEach probably does not do what you may think.
...
run spec file/s
|
|--------------> per spec file
suite callbacks (e.g., 'describe')
|
'before' root-level pre-hook
|
'before' pre-hook
|
|--------------> per test
'beforeEach' root-level pre-hook
|
'beforeEach' pre-hook
...
From the above picture, you can see that for each describe the before root-level pre-hook is called. Just turn your root-level beforeEach in a before and it should be solved.
The general rule is that before callback always come "before"(no pun intended) the beforeEach callback, independently from the level they are defined in.
You could use a describe() that has a beforeEach() and a describe() inside of it.
Something like this
describe ('A blah component', () =>
{
beforeEach(() => {
console.log('beforeEach')
})
describe(`tests`, () => {
before(() => {
console.log('before')
})
it('test 1, () => {
console.log('it')
})
})
}

why is my test skipped on jest

I have this test using jest, but the second method is getting skipped, why?
const stringToTest = JSON.stringify({"filename":"9F6148567F8.jpg","id":"ss9:blob-ref:29e4b813a","diskp":"gotchi","mikoId":"e3f813a","content":"gotchi, 18/08/13 at 11:57 AM"});
describe('regex for uri', () => {
it('should match expected URI', () => {
expect(matchUriRE.test(stringToTest)).toBe(true);
});
//below method skipped why?
it('should not be bull or undefined'), () => {
expect(matchUriRE.test(stringToTest)).not.toBeNull;
expect(matchUriRE.test(stringToTest)).not.toBe(null);
expect(matchUriRE.test(stringToTest)).not.toBeUndefined();
};
})
with result:
Test Suites: 1 passed, 1 total
Tests: 1 skipped, 1 passed, 2 total
Simple typo. Remove parenthesis after the test description and place it after closing } on the test.
it('should not be bull or undefined'), () => {
Should be
it('should not be bull or undefined', () => {
it's not the case here but just for future reference in my case it was because i added only tag by mistake
exp:
it.only("test name", () => {})
this will only run this tests and ignore the other tests in the same file

Categories