Jest: putting variable directly in describe-block vs. beforeAll - testing

I know that having shared state between tests is bad practice and should be avoided if possible. But I'm just curious how are these two constructs below different in Jest:
describe-block
describe('test suite', () => {
const theAnswer = 42;
test('a test case', () => {
expect(theAnswer + 1).toEqual(43);
});
test('another test case', () => {
expect(theAnswer + -1).toEqual(41);
});
});
vs.
beforeAll
describe('test suite with beforeAll', () => {
let theAnswer;
beforeAll(() => {
theAnswer = 42;
});
test('a test case', () => {
expect(theAnswer + 1).toEqual(43);
});
test('another test case', () => {
expect(theAnswer + -1).toEqual(41);
});
});
What's the significance of using beforeAll if we can directly declare a shared variable/state in the describe block?

From the doc One-Time Setup:
This can be especially bothersome when the setup is asynchronous, so you can't do it inline. Jest provides beforeAll and afterAll to handle this situation.
If the setup is synchronous like yours, declaring the variables in the describe block is OK.
If setup was synchronous, you could do this without beforeAll. The key is that Jest will wait for a promise to resolve, so you can have asynchronous setup as well.
But if the setup is asynchronous, you can't do it inside describe block. You must do it in before* and after* hooks.
E.g.
describe('test suite', () => {
let theAnswer;
beforeAll((done) => {
setTimeout(() => {
theAnswer = 42;
done();
}, 1_000);
});
test('a test case', () => {
expect(theAnswer + 1).toEqual(43);
});
test('another test case', () => {
expect(theAnswer + -1).toEqual(41);
});
});
Jest will wait for the setup to be done before running the test cases.
See the doc about beforeAll

Related

how to mock window.eventBus.$on - Vue.js | Jest Framework

Need to test the emitted value for test case coverage.
window.eventBus.$on('filter-search-content', () => {
console.log('Yes it was emitted');
this.showFilter = true;
});
This what i have tried. But it's not worked out for me.
it('should all the elements rendered', () => {
global.eventBus = {
$on: jest.fn(),
}
// global.eventBus.$emit('filter-search-content'); --> This also not working
wrapper = mountAppointment(data);
wrapper.vm.eventBus.$emit('filter-search-content');
expect(wrapper.vm.showFilter).toBe(true);
});
Here is the example code we can follow.
emitEvent() {
this.$emit("myEvent", "name", "password")
}
Here is the test case
describe("Emitter", () => {
it("emits an event with two arguments", () => {
const wrapper = shallowMount(Emitter)
wrapper.vm.emitEvent()
console.log(wrapper.emitted())
})
})

Change/overwrite mock data with react-testing-library and jest [duplicate]

I'd like to change the implementation of a mocked dependency on a per single test basis by extending the default mock's behaviour and reverting it back to the original implementation when the next test executes.
More briefly, this is what I'm trying to achieve:
Mock dependency
Change/extend mock implementation in a single test
Revert back to original mock when next test executes
I'm currently using Jest v21. Here is what a typical test would look like:
// __mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
myMockedModule.a = jest.fn(() => true);
myMockedModule.b = jest.fn(() => true);
export default myMockedModule;
// __tests__/myTest.js
import myMockedModule from '../myModule';
// Mock myModule
jest.mock('../myModule');
beforeEach(() => {
jest.clearAllMocks();
});
describe('MyTest', () => {
it('should test with default mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
it('should override myMockedModule.b mock result (and leave the other methods untouched)', () => {
// Extend change mock
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// Restore mock to original implementation with no side effects
});
it('should revert back to default myMockedModule mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
Here is what I've tried so far:
mockFn.mockImplementationOnce(fn)
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myMockedModule.b.mockImplementationOnce(() => 'overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
Pros
Reverts back to original implementation after first call
Cons
It breaks if the test calls b multiple times
It doesn't revert to original implementation until b is not called (leaking out in the next test)
jest.doMock(moduleName, factory, options)
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
jest.doMock('../myModule', () => {
return {
a: jest.fn(() => true,
b: jest.fn(() => 'overridden',
}
});
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
Pros
Explicitly re-mocks on every test
Cons
Cannot define default mock implementation for all tests
Cannot extend default implementation forcing to re-declare each mocked method
Manual mocking with setter methods (as explained here)
// __mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
let a = true;
let b = true;
myMockedModule.a = jest.fn(() => a);
myMockedModule.b = jest.fn(() => b);
myMockedModule.__setA = (value) => { a = value };
myMockedModule.__setB = (value) => { b = value };
myMockedModule.__reset = () => {
a = true;
b = true;
};
export default myMockedModule;
// __tests__/myTest.js
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myModule.__setB('overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
myModule.__reset();
});
Pros
Full control over mocked results
Cons
Lot of boilerplate code
Hard to maintain on long term
jest.spyOn(object, methodName)
beforeEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});
// Mock myModule
jest.mock('../myModule');
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
const spy = jest.spyOn(myMockedModule, 'b').mockImplementation(() => 'overridden');
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// How to get back to original mocked value?
});
Cons
I can't revert mockImplementation back to the original mocked return value, therefore affecting the next tests
Use mockFn.mockImplementation(fn).
import { funcToMock } from './somewhere';
jest.mock('./somewhere');
beforeEach(() => {
funcToMock.mockImplementation(() => { /* default implementation */ });
// (funcToMock as jest.Mock)... in TS
});
test('case that needs a different implementation of funcToMock', () => {
funcToMock.mockImplementation(() => { /* implementation specific to this test */ });
// (funcToMock as jest.Mock)... in TS
// ...
});
A nice pattern for writing tests is to create a setup factory function that returns the data you need for testing the current module.
Below is some sample code following your second example although allows the provision of default and override values in a reusable way.
const spyReturns = returnValue => jest.fn(() => returnValue);
describe("scenario", () => {
beforeEach(() => {
jest.resetModules();
});
const setup = (mockOverrides) => {
const mockedFunctions = {
a: spyReturns(true),
b: spyReturns(true),
...mockOverrides
}
jest.doMock('../myModule', () => mockedFunctions)
return {
mockedModule: require('../myModule')
}
}
it("should return true for module a", () => {
const { mockedModule } = setup();
expect(mockedModule.a()).toEqual(true)
});
it("should return override for module a", () => {
const EXPECTED_VALUE = "override"
const { mockedModule } = setup({ a: spyReturns(EXPECTED_VALUE)});
expect(mockedModule.a()).toEqual(EXPECTED_VALUE)
});
});
It's important to say that you must reset modules that have been cached using jest.resetModules(). This can be done in beforeEach or a similar teardown function.
See jest object documentation for more info: https://jestjs.io/docs/jest-object.
Little late to the party, but if someone else is having issues with this.
We use TypeScript, ES6 and babel for react-native development.
We usually mock external NPM modules in the root __mocks__ directory.
I wanted to override a specific function of a module in the Auth class of aws-amplify for a specific test.
import { Auth } from 'aws-amplify';
import GetJwtToken from './GetJwtToken';
...
it('When idToken should return "123"', async () => {
const spy = jest.spyOn(Auth, 'currentSession').mockImplementation(() => ({
getIdToken: () => ({
getJwtToken: () => '123',
}),
}));
const result = await GetJwtToken();
expect(result).toBe('123');
spy.mockRestore();
});
Gist:
https://gist.github.com/thomashagstrom/e5bffe6c3e3acec592201b6892226af2
Tutorial:
https://medium.com/p/b4ac52a005d#19c5
When mocking a single method (when it's required to leave the rest of a class/module implementation intact) I discovered the following approach to be helpful to reset any implementation tweaks from individual tests.
I found this approach to be the concisest one, with no need to jest.mock something at the beginning of the file etc. You need just the code you see below to mock MyClass.methodName. Another advantage is that by default spyOn keeps the original method implementation but also saves all the stats (# of calls, arguments, results etc.) to test against, and keeping the default implementation is a must in some cases. So you have the flexibility to keep the default implementation or to change it with a simple addition of .mockImplementation as mentioned in the code below.
The code is in Typescript with comments highlighting the difference for JS (the difference is in one line, to be precise). Tested with Jest 26.6.
describe('test set', () => {
let mockedFn: jest.SpyInstance<void>; // void is the return value of the mocked function, change as necessary
// For plain JS use just: let mockedFn;
beforeEach(() => {
mockedFn = jest.spyOn(MyClass.prototype, 'methodName');
// Use the following instead if you need not to just spy but also to replace the default method implementation:
// mockedFn = jest.spyOn(MyClass.prototype, 'methodName').mockImplementation(() => {/*custom implementation*/});
});
afterEach(() => {
// Reset to the original method implementation (non-mocked) and clear all the mock data
mockedFn.mockRestore();
});
it('does first thing', () => {
/* Test with the default mock implementation */
});
it('does second thing', () => {
mockedFn.mockImplementation(() => {/*custom implementation just for this test*/});
/* Test utilising this custom mock implementation. It is reset after the test. */
});
it('does third thing', () => {
/* Another test with the default mock implementation */
});
});
I did not manage to define the mock inside the test itself so I discover that I could mock several results for the same service mock like this :
jest.mock("#/services/ApiService", () => {
return {
apiService: {
get: jest.fn()
.mockResolvedValueOnce({response: {value:"Value", label:"Test"}})
.mockResolvedValueOnce(null),
}
};
});
I hope it'll help someone :)
It's a very cool way I've discovered on this blog https://mikeborozdin.com/post/changing-jest-mocks-between-tests/
import { sayHello } from './say-hello';
import * as config from './config';
jest.mock('./config', () => ({
__esModule: true,
CAPITALIZE: null
}));
describe('say-hello', () => {
test('Capitalizes name if config requires that', () => {
config.CAPITALIZE = true;
expect(sayHello('john')).toBe('Hi, John');
});
test('does not capitalize name if config does not require that', () => {
config.CAPITALIZE = false;
expect(sayHello('john')).toBe('Hi, john');
});
});

How to mock nestjs-redis with jest

I am trying to mock and spy on the redis set method in my nestjs setup, but I don't think that it is working as it should.
const mockRedis = {
set: jest.fn().mockResolvedValue(undefined),
};
const mockRedisService = {
getClient: jest.fn(() => mockRedis),
};
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
providers: [
{ provide: RedisService, useValue: mockRedisService },
],
}).compile();
});
it('...',() => {
const redisSetSpy = jest.spyOn(mockRedis, 'set');
myTestedMethod();
expect(redisSetSpy).toBeCalledWith(/* args here */);
})
I suspect that it is not possible to use spyOn with a nested method as set in this context? How should I mock redis to be able to use spyOn on set? The library used for redis in this case is nestjs-redis.
You don't have to use spyOn to check the arguements that have been passed to the function. You can simply create a jest.fn():
let mockRedisSet;
// Function that creates the testing app.
const createApp = () => {
const mockRedis = {
set: mockRedisSet,
};
const mockRedisService = {
getClient: jest.fn(() => mockRedis),
};
const moduleRef = await Test.createTestingModule({
providers: [{ provide: RedisService, useValue: mockRedisService }],
}).compile();
};
// For each test, set default mock and create testing app.
beforeEach(async () => {
mockRedisSet = jest.fn().mockResolvedValue(undefined);
createApp();
});
describe("...", () => {
// For each sub tests, set default mock and create testing app.
beforeEach(async () => {
mockRedisSet = jest.fn().mockResolvedValue(/* Specific value for sub tests */);
createApp();
});
it("...", () => {
myTestedMethod();
// Check which arguments was passed to the mock function.
expect(mockRedisSet).toHaveBeenCalledWith(/* args here */);
});
});
Creating a mock is much simpler this way as you only have to create the mocked objects and test the functions the use.
Here your spy is mockRedisSet and I reorganized your testing file so the spy function has a default value that can be overridden for specific tests. You have more control on the testing value and a default value reset for each tests so that tests don't interfer with each other.

Unit Test Rxjs 5

I am trying to write a test using mocha and chai for my observable methods that makes a call to a server and returns some json data. However, when I run the test I get the following error:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
Even when I overwrite the default timeout time, I still get the above error. What am I doing wrong ?
describe("some test", () => {
let someClass: SomeClass;
before(() => {
someClass = new SomeClass();
});
;
it("should meet some condition", done => {
let getData = someClass.getData('query')
getData.subscribe(json => {
json.success.should.equal(true);
done();
},
done
);
});
});
I found a solution, I call done() in the before hook and the set timeout on each it() function.
describe("some test", () => {
let someClass: SomeClass;
before((done) => {
someClass = new SomeClass();
done();
});
;
it("should meet some condition", done => {
let getData = someClass.getData('query')
getData.subscribe(json => {
json.success.should.equal(true);
done();
},
done
);
}).timeout(10000);
});

How to nest Vue.nextTick when testing?

I'm trying to test what happens in my app on two consecutive ticks. This is what I have so far (the tests fail in the karma devtools, but fail in the command line):
import { mount } from 'avoriaz';
import MyComponent from './MyComponent';
describe('testing', function() {
it('should do something', (done) => {
const wrapper = mount(MyComponent, { store });
wrapper.vm.changeData();
Vue.nextTick(() => {
expect(wrapper.vm.something).to.eql(somethingElse);
wrapper.vm.changeData();
Vue.nextTick(() => {
expect(wrapper.vm.something2).to.eql(somethingElse2);
done();
});
done();
});
});
});
I also tried using then() and catch(), but karma still thinks my failing tests are passing.
Should I only have one done() call? I'm not really sure what this callback is doing.
As indicated here, there is an even better solution, which prevents Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.:
it('should do something', (done) => {
const wrapper = mount(MyComponent, { store });
wrapper.vm.changeData();
Vue.nextTick(() => {
expect(wrapper.vm.something).to.eql(somethingElse);
wrapper.vm.changeData();
Vue.nextTick().then(() => {
expect(wrapper.vm.something2).to.eql(somethingElse2);
}).then(done, done);
});
});
I'd like to also use the async/await version, but I wasn't able to get it to work.