isVueInstance is deprecated and will be removed in future releases - jestjs

I am new with JEST and have received the above warning. I want to know which is the alternative since is being deprecated.
Here is the test that I am making:
it('is instantiated', () => {
expect(wrapper.isVueInstance()).toBeTruthy();
});

Here's how to rigorously check VueInstance
https://github.com/vuejs/vue-test-utils/blob/2d6b49780c7e1d663b877ddf5d6492ed7b510379/packages/test-utils/src/wrapper.js#L400
it('is instantiated', () => {
expect(wrapper.vm).toBeTruthy();
});

I have checked https://vue-test-utils.vuejs.org/api/wrapper/#isvisible and they say:
Assert Wrapper is Vue instance.
So the final thing would be:
it('is instantiated', () => {
expect(wrapper).toBeTruthy();
});

The right answer should be the following:
it('is instantiated', () => {
expect(wrapper.exists()).toBeTruthy();
});
From test/specs/wrapper/find.spec.js in vue-test-utils repository,
you can see that when wrapper doesnt exists they assert Wrapper object with exists().
it('returns empty Wrapper with error if no nodes are found', () => {
const wrapper = mountingMethod(Component)
const selector = 'pre'
const error = wrapper.find(selector)
expect(error.exists()).toEqual(false)
expect(error.selector).toEqual(selector)
})

Related

Why is my resetAllMocks not working in jest

The second expect(fs.writeFile).toHaveBeenCalledTimes(1) (in describe('Guid for MPX') returns an error because the writeFile has been called twice. In theory, jest.ResetAllMocks should take care of this but it doesn’t.
'use strict';
const fs = require('fs').promises;
const path = require('path');
const guidForMpxInvalid = require('../json/guid-for-Mpx-invalid.json')
const data = require('../../../data/sandbox-data-model.json');
jest.mock('fs', () => ({
promises: {
writeFile: jest.fn(),
},
}));
const {
writeData,
createGuidForMpx,
createMpxForGuid,
} = require('../app/transform');
const directoryPath = path.join(__dirname, '../../../wiremock/stubs/mappings');
describe('Write file', () => {
beforeEach(() => {
jest.resetAllMocks();
});
it('should write a file', async () => {
const result = await writeData(guidForMpxInvalid, 'guid-for-Mpx-invalid-Mpx.json');
expect(result).toEqual('guid-for-Mpx-invalid-Mpx.json written');
expect(fs.writeFile).toHaveBeenCalledTimes(1);
});
});
describe('Guid for MPX', () => {
it('should create JSON file for the GUID of a particular MPX', async ()=>{
const result = await createGuidForMpx(data.Customers[0].guid, data.Customers[0].Customer_Overlays.core.Personal_Details.MPX);
expect(result).toEqual('guid-for-Mpx-AB123456B.json written');
expect(fs.writeFile).toHaveBeenCalledTimes(1);
});
});
The code being called:
const writeData = async (data, file) => {
const directoryPath = path.join(__dirname, '../../wiremock/stubs/mappings');
try {
fs.writeFile(`${directoryPath}/${file}`, data);
return `${file} written`
} catch (err) {
return err;
}
};
I was experiencing the same problem until I placed jest.resetAllMocks(); inside afterEach like so:
afterEach(() => {
jest.resetAllMocks();
});
I eventually got this working by creating a spy for the writefile at the start of each test and clearing it when the test is done:
it('should write a file', async () => {
const writeFileSpy = jest.spyOn(fs, 'writeFile');
const result = await writeData(guidForMPXInvalid, 'guid-for-mpx-invalid-mpx.json');
expect(result).toEqual('guid-for-mpx-invalid-mpx.json written');
expect(writeFileSpy).toHaveBeenCalledTimes(1);
writeFileSpy.mockClear();
});
});
Same thing here. I had to use spyOn as well, which is probably better practice.
All should beware when not using spyOn with complex libraries, double check that your reset works, but safe practice is to manually restore the function you mocked.
There is an issue it seems, perhaps because how fs/promises is included. fs.promises is a Getter function and is lazy loaded from internal/fs/promises, and jest is seemingly unable to clean lazy loaded modules with jest.resetModules?
See related note by #john-james regarding moduleNameMapper:
Jest not working with fs/promises typescript
Another documented error with resetModules():
https://github.com/facebook/jest/issues/11632

Unmock function after mockimplementation

I'm having a bit of trouble unmocking a function.
I first mock it and now I can't unmock it
//myClass.js
class myClass {
static check(v1,v2) {
return v1 > v2;
}
static async getinfo(v1,v2) {
if (this.check(v1,v2)) {
return await get('api.google.com');
}
return [];
}
}
//myclass.spec.js
describe('Testing myClass', () => {
describe('testing processing', () => {
it('should return result', () => {
const mockPatch = jest.fn().mockImplementation((version, solution) => false);
myClass.check = mockCheck;
try {
const result = await myClass.getinfo(1,2);
expect(result).toBe.([]);
}catch(e) {
throw e;
}
})
})
describe('Testing check', () => {
it('should return true', () => {
expect(myClass.check(2,1)).toBe.true
})
})
})
I already try with
myClass.check.mockRestore()
beforeEach(() => {myClass.check.mockRestore()})
jest.unmock('./myClass.js)
Is there anyway I can solve this? I read all the jest doc and i couldn't find anything
Methods should never be mocked by reassigning them, there is no way how Jest could restore their original implementation this way.
This should always be done with spyOn:
jest.spyOn(myClass, 'check').mockReturnValue(false)
This way a method can be restored with restoreMock or restoreAllMocks. This should be preferably enabled globally in Jest configuration.
I'm assuming that what you're hoping to do is to mock an implementation for use in a specific test, but then have your other tests function without the mocking.
If so, I think you could use the module mocking strategy in conjunction with mockReturnValueOnce.
Be sure to import your module at the top of your tests, then to call jest.mock with the same path. After that, you should be able to call myClass.check.mockReturnValueOnce, and it will be mocked until the next time it is called. After that, it will function normally 👍

spyOn #react-native-firebase/analytics methods

Basically, I want to make sure the methods of analytics are called with certain properties but so far it is not working:
Cannot spy the logAppOpen property because it is not a function; undefined given instead
the library is successfully mocked since I can see console log out of my jest.fn():
jest.mock('#react-native-firebase/analytics', () => {
return () => ({
logAppOpen: jest.fn(() => console.log('mocked fun called')), //===>shown correctly
})
})
My class is:
import analytics from '#react-native-firebase/analytics';
export default class GA {
appStarted = async () =>{
console.log('appStarted called'); //==> showing
await analytics().logAppOpen();
}
}
my test:
it("should log app starting", async () =>{
const spy = jest.spyOn(analytics, 'logAppOpen') //===>FAILS HERE
congst ga = new GA();
await ga.appStarted();
expect(spy).toHaveBeenCalled();
})
but in my test: console.log(analytics) does show an empty object {}
It's analytics().logAppOpen() while jest.spyOn tries to spy on analytics.logAppOpen which doesn't exist.
For lazily evaluated spied functions it's easier to expose them as variables:
const mockLogAppOpen = jest.fn();
jest.mock('#react-native-firebase/analytics', () => {
return jest.fn()
.mockReturnValue({ logAppOpen: mockLogAppOpen });
});
This way it can be accessed for call assertions. There's no need for jest.spyOn for a function that is already a spy.

Jest: child_process.exec.mockImplentation is not a function

I have a function that uses the child_process.exec function:
//serverUtils.js:
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
async getUpstreamRepo() {
try {
const forkConfig = (await exec('git remote get-url upstream')).stdout;
let upstreamRepo = forkConfig.replace('git#github.com:', '');
upstreamRepo = upstreamRepo.replace(/\r?\n|\r/g, '');
return upstreamRepo;
} catch (error) {
console.error(error);
throw error;
}
},
After looking at this SO post, I tried to mock the exec call like so:
//serverUtils.test.js:
const child_process = require('child_process');
jest.mock('child_process')
describe('Test Class', () => {
....
it('check upstream repo', async () => {
child_process.exec.mockImplentation(jest.fn().
mockReturnValueOnce('git#github.com:mock/url.git'))
await expect(serverScript.getUpstreamRepo()).
resolves.toEqual('mock/url.git');
});
}
However, I get child_process.exec.mockImplentation is not a function
As the linked post explains, "Jest documentation says that when mocking Node's core modules calling jest.mock('child_process') is required." -- which I clearly do.
The error you are seeing is because you are calling mockImplentation instead of mockImplementation. Unfortunately, when you correct that typo the test still will not pass.
This is because you are calling promisify on exec method, allowing it to be used as a promise. What promisify does under the hood is transform from an asynchronous callback based function (where the callback is placed at last parameter and is called with error as first parameter and data as second) to a promise based function.
So, in order for the promisify method to work, you will have to mock the exec method so that it calls the callback parameter in order for the promise to resolve.
Also, note that you are reading the stdout parameter from the result of the exec call, so in the returned data you will have to send an object with that property.
Having all that into account:
it('check upstream repo', async () => {
child_process.exec.mockImplementation((command, callback) => {
callback(null, { stdout: 'git#github.com:mock/url.git' });
});
await expect(serverScript.getUpstreamRepo()).
resolves.toEqual('mock/url.git');
});
Another posible solution is to directly mock the promisify method:
jest.mock('util', () => ({
promisify: jest.fn(() => {
return jest.fn().mockResolvedValue({ stdout: 'git#github.com:mock/url.git' });
})
}));
describe('Test Class', () => {
it('check upstream repo', async () => {
await expect(serverScript.getUpstreamRepo()).
resolves.toEqual('mock/url.git');
});
});

Disable a single nock scope immediately to re-setup a mocked URL

Using nock, is there a way to disable a single nock scope?
I've been struggling with some tests that set up nocks of the same URL as some other tests. They both run fine separately, but when run in the same mocha session one of them fails, because I'm unable to re-nock the active nock scopes, meaning the nocks that were set up catches all the requests.
What I've tried:
If I set up some nocks in before() and then call scope.persist(false) in my after(), it only "unpersists" the scope, so that it's active for one more request. It does not immediately disable it.
I've found that nock.cleanAll() immediately disables the nocks so that they can be set up again, but then it also disables any global nocks that may have been set up once, common to all test cases.
So far, the only solutions I've found are 1) use unique URL:s for all nocks, which isn't always possible or 2) use nock.cleanAll() and don't rely on any global nocks - instead make sure to only set up nocks in local before() functions, including setting up the global ones repeatedly for every test that needs them.
It seems it would be highly useful to be able to do
scope = nock('http://somewhere.com').persist().get('/'.reply(200, 'foo');
and then use that nock in a bunch of tests, and finally do
scope.remove();
However, I've not been able to do something like this. Is it possible?
Example:
before(async () => {
nock('http://common').persist().get('/').reply(200, 'common');
});
after(async () => {
});
describe('Foo tests', () => {
let scope;
before(async () => {
scope = nock('http://mocked').persist().get('/').reply(200, 'foo');
});
after(() => {
// scope.persist(false); // This causes the Bar tests to use the Foo nocks one more time :(
// nock.cleanAll(); // This also disables the common nocks
});
it('Should get FOO', async () => {
expect(await fetch('http://mocked').then(res => res.text())).to.equal('foo');
expect(await fetch('http://common').then(res => res.text())).to.equal('common');
});
it('Should get FOO again', async () => {
expect(await fetch('http://mocked').then(res => res.text())).to.equal('foo');
expect(await fetch('http://common').then(res => res.text())).to.equal('common');
});
});
describe('Bar tests', () => {
let scope;
before(async () => {
scope = nock('http://mocked').persist().get('/').reply(200, 'bar');
});
after(() => {
// scope.persist(false);
// nock.cleanAll();
});
it('Should get BAR', async () => {
expect(await fetch('http://mocked').then(res => res.text())).to.equal('bar');
expect(await fetch('http://common').then(res => res.text())).to.equal('common');
});
it('Should get BAR again', async () => {
expect(await fetch('http://mocked').then(res => res.text())).to.equal('bar');
expect(await fetch('http://common').then(res => res.text())).to.equal('common');
});
});
These tests either fail the 3rd test if using scope.persist(false) (since that test still gets the foo version), or fails tests 3 and 4 if using nock.cleanAll(), since the common nocks are then removed.
I also had this issue and found a way to work around it by listening to the request event emitted by the scope and removing the interceptor when the event is fired. Ideally, I think you should be listening to the replied event but for some reason, that event wasn't firing when I tried it, not sure why. But the code below worked for me:
/**
* #jest-environment node
*/
const nock = require('nock');
describe('Test suite', () => {
test('Test case', async () => {
let interceptor1 = nock('https://example-url.com', {
reqHeaders: {
'Content-Type': 'text/xml',
soapaction: 'http://www.sample.com/servie/getOrders',
},
})
.post('/');
let interceptor2 = nock('https://example-url.com', {
reqHeaders: {
soapaction: 'http://www.sample.com/servie/getProducts',
},
})
.post('/');
let scope = interceptor1.replyWithFile(200, path.join(__dirname, './path1.xml'));
interceptor2.replyWithFile(200, path.join(__dirname, './path.xml'));
scope.on('request', (req, interceptor) => {
nock.removeInterceptor(interceptor1);
});
const resp = await asynccall();
expect(resp).toStrictEqual(exp);
});
});
As described here: Unable to remove interceptors using nock I found a way of not storing the interceptors by just setting the mock again (which apparently returns the interceptor again) and then using the returned interceptor in the removeInterceptor() function. This returns true indeed and does work in my tests.
I found a pretty simple workaround for this one - the scope has a property called "interceptors", which is an array of the various interceptors the scope uses. You can replace the "body" property of the interceptor with whatever you want.
let scope = nock(base).get(path).reply(200, []).persist();
testable.call(path).then(console.log); //returns []
scope.interceptors[0].body = [1,2,3];
testable.call(path).then(console.log); //returns [1,2,3]

Resources