How to test a vue method with mocha Chai - vue.js

This is MOCHA CHAI unit test : users.spec.js :
import { expect } from "chai";
import { shallowMount } from "#vue/test-utils";
import Users from "#/components/Users.vue";
const wrapper = shallowMount(Users);
describe("Users test", () => {
it("Displays nice hello message", () => {
expect(wrapper.vm.$data.msg).to.equal("Welcome to Crypto Info");
});
it("users model is an array", () => {
expect(wrapper.vm.$data.users).to.be.an("array");
});
it("getUsers() to be a function", () => {
expect(wrapper.vm.$methods.getUsers()).to.be.a("function");
});
});
I can't find the correct syntax for my third test . I've tried plenty of things . $methods.getUsers() is not working .
1) Users test
getUsers() to be a function:
TypeError: Cannot read property 'getUsers' of undefined
at Context.it (dist\js\webpack:\tests\unit\users.spec.js:15:1)
Could you please help me?
Thank you .

The method would simply be defined as a property of the wrapper.vm, so you could verify the method exists with:
expect(wrapper.vm.getUsers).to.be.a("function")

Could you do something like
const result = typeOf wrapper.vm.$methods.getUsers();
Then test the result is a string with value "function"?
expect(result).to.equal("function");
Is that any use to you?

Related

How Test with Jest a function in the method "mounted" VueJS

I would to try call a function already mocked. I use vueJS for the frond and Jest as unit test. Below a example of my code. My purpose is to test the call of « anotherFunction". The first test is succeed , not the second.Thanks for help or suggestion
code vueJS:
mounted() {
this.myfunction();
}
methods: {
myfunction() {
this.anotherFunction();
}
}
Jest code:
describe('Home.vue', () => {
let wrapper = null;
const options = {
mocks: {
$t: () => 'some specific text',
},
methods: {
myFunction: jest.fn(),
},
};
it('Should renders Home Component', () => {
// Given
wrapper = shallowMount(Home, options);
// Then
expect(wrapper).toBeTruthy();
});
it('Should call anotherFunction', async (done) => {
// Given
wrapper.vm.anotherFunction = jest.fn().mockResolvedValue([]);
// When
await wrapper.vm.myFunction();
// THIS THE PROBLEM, myFunction is mocked and I can't call the function 'anotherFunction' inside...
// Then
// expect(wrapper.vm.anotherFunction).toHaveBeenCalled();
});
});
I was finding a good way to help you if this test case. So, I thought in something like the chuck code below:
import { mount } from '#vue/test-utils';
describe('Home', () => {
it('method calls test case', () => {
const anotherMethodMock = jest.fn();
wrapper = mount(Home, {
methods: {
anotherMethod: anotherMethodMock
}
});
expect(anotherMethodMock).toHaveBeenCalled();
});
});
But, the Jest threw the following exception:
[vue-test-utils]: overwriting methods via the methods property is deprecated and will be removed in the next major version. There is no clear migration path for themethods property - Vue does not support arbitrarily replacement of methods, nor should VTU. To stub a complex m ethod extract it from the component and test it in isolation. Otherwise, the suggestion is to rethink those tests.
I had the following insight, maybe, in this case, should be better to test the side effect of this anotherMethod calling. What does it change? Is something being shown to the user?
I believe that here we have started from the wrong concept.
I hope that this tip could be useful :)
As suggested by #Vinícius Alonso, We should avoid using methods and setMethods in our test cases because of it's deprecation. But you can still test the mounted lifecycle by mocking the functions that are being called during mount. So you can do something similar to below snippet.
describe('Mounted Lifecycle', () => {
const mockMethodOne = jest.spyOn(MyComponent.methods, 'methodOne');
const mockMethodTwo = jest.spyOn(MyComponent.methods, 'methodTwo');
it('Validate data and function call during mount', () => {
const wrapper = shallowMount(MyComponent);
expect(mockMethodOne).toHaveBeenCalled();
expect(mockMethodTwo).toHaveBeenCalled();
})
})
Do mount/shallowMount inside it only rather putting it outside of it as it was not working in my case. You can checkout more details on it if you want.

Jest Mocking Permissions of Expo TypeError: Cannot read property 'askAsync' of undefined

I'm mocking expo and the Permissions module, but when calling Permissions.AskAsync Permissions is undefined.
Problem looks like this question. Using Jest to mock named imports
Used the provided answer, but did not work.
I have mocked the axios, which works. Doing the same for the expo module does not work.
The function I want to test:
checkPermission = async () => {
const {statusCamera} = await Permissions.askAsync(Permissions.CAMERA);
// console.log(statusCamera);
this.setState({cameraPermission: statusCamera});
const {statusCameraRoll} = await Permissions.askAsync(Permissions.CAMERA_ROLL);
this.setState({cameraRollPermission: statusCameraRoll});
};
The test:
describe("Test the Permission function", () => {
it('should return rejected permission.', async function () {
const wrapper = shallow(<Photo2/>);
const instance = wrapper.instance();
await instance.checkPermission();
expect(instance.state("cameraPermission")).toBeFalsy();
});
});
The mock I use for expo:
jest.mock('expo', ()=>({
Permissions: {
askAsync: jest.fn()
}
}))
and tried
(In file mocks/expo.js)
export default {
Permissions: {
askAsync: jest.fn(() => {
return "SOMETHING"
})
}
}
and tried
(In file mocks/expo.js)
jest.mock('expo', ()=>({
Permissions: {
askAsync: jest.fn()
}
}));
Error: "TypeError: Cannot read property 'askAsync' of undefined"
This error occures on line where Permissions.askAsyc is called. So Permissions is undefined. (Also checked it with console.log(Permissions)
I expected the instance.state("cameraPermission") to be falsy, but it crashes before it comes to that line.
Since expo change the packages to be import * as Permissions from 'expo-permissions';
You just need to create "mocks/expo-permissions.js" and have it has:
export const getAsync = jest.fn(permissions => Promise.resolve());
export const askAsync = jest.fn(permissions => Promise.resolve());
teerryn's answer is correct and is a good start. To add some more details:
Unless you've configured different roots for Jest, you should place your mock file in __mocks__/expo-permissions.js where __mocks__ is a directory at the same level as your node_modules folder. See Jest docs on mocking node modules.
The permissions argument being passed in will be undefined due to the way we're mocking the module, so you'll need to mock the permission types you want to use. Just need something simple like export const CAMERA_ROLL = 'camera_roll';
If you want to respond differently based on the permission type passed in (for example, allow Permissions.CAMERA but deny Permissions.CAMERA_ROLL and all other types), you can mock the implementation of the askAsync function. For example, your __mocks__/expo-permissions.js file would look like this:
export const CAMERA = 'camera';
export const CAMERA_ROLL = 'camera_roll';
export const askAsync = jest.fn().mockImplementation((permissionType) => {
const responseData = permissionType === CAMERA ? { status: 'granted' } : { status: 'undetermined' }; // you could also pass `denied` instead of `undetermined`
return Promise.resolve(responseData);
});
The problem is that you are handling async tests incorrectly (your checkPermission() function is async). There are several ways you can tell jest that you want to test an async function. Here are a few ways.
Here is a quick solution to your problem:
...
import { Permissions } from 'expo';
...
jest.mock('expo', () => ({
Permissions: {
askAsync: jest.fn(),
}
}));
...
describe("Test the Permission function", () => {
it('should return rejected permission.', () => {
Permissions.askAsync.mockImplementation( permission => { return {status: 'granted'}; } ); // if you want to add some sort of custom functionality
const wrapper = shallow(<Photo2/>);
const instance = wrapper.instance();
return instance.checkPermission().then(data => {
expect(instance.state("cameraPermission")).toBeFalsy();
});
});
});

How to unit test Vue.js components that use nuxt-i18n

If I try to run the thing below (with yarn run jest), I get TypeError: _vm.$t is not a function, because SearchField is using a translation ("$t('search')").
import { mount } from "#vue/test-utils";
import SearchField from "#/components/ui/SearchField";
describe("SearchField", () => {
const wrapper = mount(SearchField);
it("renders correctly", () => {
expect(wrapper.element).toMatchSnapshot();
});
});
If I add the following three lines at the beginning, I get TypeError: Cannot read property '_t' of undefined instead.
import Vue from "vue";
import VueI18n from "vue-i18n";
Vue.use(VueI18n);
nuxt-i18n is an external library, not your own code, so the test good practices ask us to just mock the translation library and its needed functions ($t in this case).
The following code should solve your problem:
describe("SearchField", () => {
const wrapper = mount(SearchField);
it("renders correctly", () => {
mocks: {
$t: (msg) => msg
}
expect(wrapper.element).toMatchSnapshot();
});
});
More information on this approach can be found here.

Jest + Nuxt + Nuxt-Fire is failing in test suite

I'm using Nuxt with Nuxt-Fire (https://github.com/lupas/nuxt-fire)
When I launch my test I get this error [Vue warn]: Error in config.errorHandler: "TypeError: Cannot read property 'ref' of undefined"
This is happening because of this section in my App
mounted() {
this.initiate(window.instaroomId)
let connected = this.$fireDb.ref(".info/connected")
this.getConnection(connected)
},
It looks like the this.$fireDb is not called. The module is normally loaded in nuxt.config.js. How can I make this work?
If you want to test, that this.$fireDb.ref(".info/connected") was called you can mock it like this:
import { shallowMount } from '#vue/test-utils'
import SomeComponent from '#/components/SomeComponent/SomeComponent.vue'
let wrapper
describe('SomeComponent.vue Test', () => {
beforeEach(() => {
wrapper = shallowMount(SomeComponent, {
mocks: {
$fireDb: {
ref: jest.fn()
}
}
})
})
it('$fireDb.ref was called', () => {
expect(wrapper.vm.$fireDb.ref).toBeCalled()
expect(wrapper.vm.$fireDb.ref).toBeCalledWith('.info/connected')
})
})
Or if you want the test just to pass created() hook and test another functionality you can just mock $fireDb.ref without testing that it was called.

How to expect the number of dom in karma+enzyme

I follow this link 'https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md' to write an unit test as below:
import { shallow } from 'enzyme';
import React from 'react';
import TextField from 'material-ui/TextField'
describe('Question Test Suite', () => {
it('should render one <TextField/> components', () => {
const wrapper = shallow(<QuestionForm />, { context: {router: {} }});
expect(wrapper.find(TextField)).to.have.length(1);
});
});
when run the test case I got below error:
TypeError: expect(...).length is not a function
TypeError: Cannot read property 'have' of undefined
What wrong with my test case? Is there anything I am missing there?
Your syntax is wrong.The below syntax should work fine.
expect(wrapper.find('TextField').length).toEqual(1);