how to configure all cmmon file in jest? - jestjs

how to load all common file in jest.config
how to load all common file and 3td party library's like jquery
{
"name": "my-project",
"jest": {
setupFiles:[../src/assert]
}
}

You can use setupFiles in jest.config.js. Assign the jquery and moment to node.js global object. Then, you can get the them in each test cases using global.$ and global.moment.
E.g.
setup.js:
const jquery = function () {
return "I'm fake jquery";
};
const moment = function () {
return "I'm fake moment";
};
global.$ = jquery;
global.moment = moment;
jest.config.js:
module.exports = {
preset: 'ts-jest/presets/js-with-ts',
testEnvironment: 'enzyme',
setupFilesAfterEnv: [
'jest-enzyme',
'./jest.setup.js',
],
setupFiles: [
'/Users/ldu020/workspace/github.com/mrdulin/react-apollo-graphql-starter-kit/stackoverflow/61727628/setup.js',
],
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
verbose: true,
};
a.test.js:
describe('61727628', () => {
describe('a', () => {
it('should pass', () => {
console.log('global.$:', global.$);
console.log('global.moment:', global.moment);
expect(1 + 1).toBe(2);
});
});
});
b.test.js:
describe('61727628', () => {
describe('b', () => {
it('should pass', () => {
console.log('global.$:', global.$);
console.log('global.moment:', global.moment);
expect(1 + 1).toBe(2);
});
});
});
unit test results:
PASS stackoverflow/61727628/a.test.js
61727628
a
✓ should pass (28ms)
console.log
global.$: function () {
return "I'm fake jquery";
}
at Object.<anonymous> (stackoverflow/61727628/b.test.js:4:15)
console.log
global.$: function () {
return "I'm fake jquery";
}
at Object.<anonymous> (stackoverflow/61727628/a.test.js:4:15)
console.log
global.moment: function () {
return "I'm fake moment";
}
at Object.<anonymous> (stackoverflow/61727628/a.test.js:5:15)
console.log
global.moment: function () {
return "I'm fake moment";
}
at Object.<anonymous> (stackoverflow/61727628/b.test.js:5:15)
PASS stackoverflow/61727628/b.test.js
61727628
b
✓ should pass (28ms)
Test Suites: 2 passed, 2 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 6.026s, estimated 16s

Related

Jest SuperTest: Giving error in Open Handler when using setTimeout in the class-under-test

i am writing a E2E in Jest/Supertest in Nest JS (node) environment.
I have searched extensively about this pretty common error:
Jest has detected the following 1 open handle potentially keeping Jest from exiting:
Implemented every solutions suggested.
However getting this in a setTimeout method intermittently as follows:
Test Suites: 2 passed, 2 total
Tests: 6 passed, 6 total
Snapshots: 0 total
Time: 135.464 s
Ran all test suites.
Jest has detected the following 1 open handle potentially keeping Jest from exiting:
● Timeout
49 | },
50 | delay(millisecond: number) {
> 51 | return new Promise((resolve) => setTimeout(resolve, millisecond));
| ^
52 | },
53 | };
54 |
Here is my setTimeout code:
// The API
async create<T>(key: string, item: T): Promise<T> {
await this.delay(5000);
return this.createWithoutDelay(key, item);
}
// The delay method code
delay(millisecond: number) {
return new Promise((resolve) => setTimeout(resolve, millisecond));
},
My tests are very simple:
beforeAll(async () => {
jest.clearAllMocks();
......
app = moduleUnderTest.createNestApplication();
await app.init();
// Reference the server instance
server = app.getHttpServer();
});
it('Test: Create Object', async () => {
const response = await request(server).post('/object')
.send({
name: 'new-object',
});
expect(response.status).toEqual(HttpStatus.CREATED);
expect(response.body).toBeDefined();
expect(Array.isArray(response.body)).toBeFalsy();
const jsonResponse = JSON.parse(response.text);
expect(jsonResponse.name).toEqual('new-object');
});
afterAll(async () => {
await app.close();
await server.close();
});
The following are my Jest config:
module.exports = {
moduleFileExtensions: ["js", "json", "ts"],
verbose: true,
preset: "ts-jest",
rootDir: ".",
testTimeout: 15000,
fakeTimers: {
timerLimit: 15000,
},
testEnvironment: "node",
testRegex: ".e2e-spec.ts$",
transform: {
"^.+\\.(t|j)s$": "ts-jest"
},
moduleNameMapper: {
'^axios$': require.resolve('axios'),
},
};
In the Jest cmd, I am passing: --runInBand --forceExit --detectOpenHandles
Any clue shall be helpful.

jest change mocked value at later stage

I have a mock where it sets up a return value before all my tests. But I was wondering if you could update a value in the test itself. As you can see I want to just update the boolean value of mockedIsloading, without calling the entire mockedLoadStatus.mockReturnValue({...}) again in my test with a new isLoading value of true this time around.
Would be nice to just be able to call mockedIsloading.mockReturnValueOnce(true) but this does not seem to work.
import {
loadStatus,
} from 'pathToMyFile'
jest.mock('pathToMyFile')
const mockedLoadStatus jest.mocked(loadStatus)
const mockedMutate = jest.fn()
const mockedIsLoading = jest.fn().mockReturnValue(false)
beforeAll(() => {
mockedLoadStatus.mockReturnValue({
mutate: mockedMutate,
isLoading: mockedIsloading,
})
})
test('my test', () => {
mockedIsloading.mockReturnValueOnce(true)
render(<Wrapper />)
})
What do you mean "doesn't work"? I mean this works OK:
const mockedLoadStatus = jest.fn();
const mockedMutate = jest.fn()
const mockedIsLoading = jest.fn().mockReturnValue(false)
beforeAll(() => {
mockedLoadStatus.mockReturnValue({
mutate: mockedMutate,
isLoading: mockedIsLoading,
})
})
test('some test', () => {
expect(mockedLoadStatus().isLoading()).toBeFalsy();
})
test('my test', () => {
mockedIsLoading.mockReturnValueOnce(true)
expect(mockedLoadStatus().isLoading()).toBeTruthy();
expect(mockedLoadStatus().isLoading()).toBeFalsy();
})
Or am I missing something :) ?

Jest Mocks Behavior is Inconsistent

I can't figure out why my jest mocks aren't working consistently. I understand the behavior about mocks being lifted, but I don't see how/why that would break my code in this case.
The following works
import fetchMock from 'jest-fetch-mock';
fetchMock.enableMocks();
fetchMock.dontMock();
fetchMock.doMockIf('...', async () => {
return JSON.stringify([
{
AccountName: '...'
}
]);
});
describe('....', () => {
let sut = ....
....
and my fetch call is mocked
If I do the following, my mock fetch is never called
import './mocks';
describe('....', () => {
let sut = ....
....
mocks.ts:
import fetchMock from 'jest-fetch-mock';
fetchMock.enableMocks();
fetchMock.dontMock();
fetchMock.doMockIf('...', async () => {
return JSON.stringify([
{
AccountName: '...'
}
]);
});

Jest doMock the same method multiple times

I would like to test following part of the code:
// ... code above
const created = async payload => {
const model = await db.collection('models').doc(payload.model)
.get() // <--- 1st .get() occurence
if (!model.exists) {
// Add product to the orphans collection
await db.collection('orphans').doc(payload.sku).set(payload)
} else {
// Grab the categories field
const categories = model.get('categories') // <--- 2nd .get() occurence
// Product is either empty or does not exists at all
if (!categories || categories.length < 1) {
// Add product to the orphans collection
await db.collection('orphans').doc(payload.sku).set(payload)
} else {
// Otherwise remove from the orphans collection
await deleted(payload.sku)
}
}
}
I do not know how to properly mock the file twice in the same callback. Here is what I get:
test.only('it should react when an event "created" has been fired', async () => {
const spy = jest.fn()
jest.doMock('#google-cloud/firestore', () => class {
collection () {
return {
doc: () => {
return {
get: () => {
return {
exists: () => {
spy()
}
}
},
set: () => {
spy()
}
}
}
}
}
})
const observer = require('./product')
await observer('created', {})
await expect(spy.mock.calls.length).toBe(1)
})
I get this error:
● it should react when an event "created" has been fired
TypeError: model.get is not a function
25 | } else {
26 | // Grab the categories field
> 27 | const categories = model.get('categories')
| ^
28 |
29 | // Product is either empty or does not exists at all
30 | if (!categories || categories.length < 1) {
at created (app/observers/product.js:27:30)
at Object.<anonymous>.module.exports (app/observers/product.js:6:28)
at Object.<anonymous> (app/observers/product.spec.js:34:3)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 skipped, 2 total
Snapshots: 0 total
Time: 0.147 s, estimated 1 s
Ran all test suites matching /app\/observers\/product.spec.js/i.
What is the working solution to test two scenarios of the same mocked get() method ?
In your code :
const model = await db.collection('models').doc(payload.model)
.get() // <--- 1st .get() occurence
If we look at your mock, the get method of doc returns :
{
exists: () => {
spy()
}
}
There are no property named get, so it is undefined (and not a function).
I guess you just have to change this part to :
{
exists: true, // can be false
get: spy,
}
And your problem should be solved.
Btw, you can also change the mock of set method to set: spy. Or you can keep it to set: () => { spy() }, but you should at least return the value if you want to mock it : set: () => { spy() }.
Now, about how to properly mock multiple times, here's what you can do :
const observer = require('./product')
const spyGet = jest.fn()
const spySet = jest.fn() // I like having different mocks, if one function use get & set, tests will be clever & more readable if you use different spies
describe('on event "created" fired', () => {
const categories = []
beforeEach(() => {
// I put mocks here to make test more readable
jest.doMock('#google-cloud/firestore', () => class {
collection () {
return {
doc: () => {
return {
get: () => {
return {
exists: true,
get: spyGet,
}
},
set: spySet
}
}
}
}
})
spyGet.mockResolvedValueOnce(categories) // you can also use mockResolvedValue, but mockResolvedValueOnce allow you to mock with different values on the same test & same mock
})
it.only('should get categories', async () => {
await observer('created', {})
// here's all the ways you can test it
expect(spyGet).toBeCalledTimes(1)
expect(spyGet.mock.calls.length).toBe(1)
expect(spyGet).toBeCalledWith('categories')
expect(spyGet).toHaveBeenNthCalledWith(1, 'categories')
})
})
Note : You should reset & clear your mocks between tests manually (in a afterEach or beforeEach) if you don't set it into jest config.

Sinon stub replaces class property for whole test file instead of describe block

I'm trying to replace a static method of a class so that it returns custom value for testing purposes.
I have multiple test (describe) blocks in my file, and my goal is to replace the static method only in one of the describe blocks.
The problem is that the method is replaced for all the tests, even though I have a teardown method that is replacing the static method with the original method.
Some code:
class Cat {
static sound() {
return "Meow";
}
}
module.exports = {
Cat
}
const sinon = require("sinon");
const { Cat } = require("./myClass");
describe("Main tests", () => {
describe("Test Cat", () => {
it("Meows", () => {
expect(Cat.sound()).toBe("Meow")
})
})
describe("Test Dog", () => {
const stub = sinon
.stub(Cat, "sound")
.callsFake(() => "Woof");
afterAll(() => {
stub.restore();
});
it("Barks", () => {
expect(Cat.sound()).toBe("Woof")
})
})
})
Test results - the unreplaced test case is failing:
FAIL ./index.test.js
Main tests
Test Cat
✕ Meows (6ms)
Test Dog
✓ Barks
● Main tests › Test Cat › Meows
expect(received).toBe(expected) // Object.is equality
Expected: "Meow"
Received: "Woof"
7 | describe("Test Cat", () => {
8 | it("Meows", () => {
> 9 | expect(Cat.sound()).toBe("Meow")
| ^
10 | })
11 | })
12 |
Is there a way how to prevent this?
I tried using createSandbox:
const sandbox = sinon.createSandbox()
const stub = sandbox
.stub(Cat, "sound") // etc
but it's the same thing.
Any help would be appreciated.
This task can be done easily with jestjs only (without sinon).
Just use jest.spyOb function to spy sound function, and you can mock the result of this function:
const { Cat } = require('./myClass');
describe('Main tests', () => {
beforeEach(() => {
jest.spyOn(Cat, 'sound');
});
afterEach(() => {
jest.resetAllMocks();
});
describe('Test Cat', () => {
it('Meows', () => {
// Don't mock, just call actual logic
expect(Cat.sound()).toBe('Meow');
});
});
describe('Test Dog', () => {
it('Barks', () => {
Cat.sound.mockReturnValue('Woof'); // mock return value of `sound()`
expect(Cat.sound()).toBe('Woof');
});
});
});

Resources