Mocking WebGLRenderer and other three js Libraries to test using jest - vue.js

I am trying to mock three.js import and tried to create the webgl context using jest but I always get
Error in mounted hook: "TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'."
this is because the webgl:- renderer.domelement does not return the canvas element in the mock. below is my code that I am trying to perform
jest.mock('three', () => {
const THREE = require.requireActual('three')
return {
...THREE,
WebGLRenderer: class WebGlRenderer {
WebGlRenderer () {
this.renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true, shadowMap: { enabled: true } })
return this.renderer
}
setSize () { return jest.fn() }
setPixelRatio () { return jest.fn() }
setClearColor () { return jest.fn() }
}
}
})
Expected is, it should append the domelement(i.e. HTMLCanvas element to the existing document.body)

Here's how I managed to mock WebGlRenderer:
jest.mock('three', () => {
const THREE = jest.requireActual('three');
return {
...THREE,
WebGLRenderer: jest.fn().mockReturnValue({
domElement: document.createElement('div'), // create a fake div
setSize: jest.fn(),
render: jest.fn(),
}),
};
});

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())
})
})

How to mock vue composable functions with jest

I'm using vue2 with composition Api, vuex and apollo client to request a graphql API and I have problems when mocking composable functions with jest
// store-service.ts
export function apolloQueryService(): {
// do some graphql stuff
return { result, loading, error };
}
// store-module.ts
import { apolloQueryService } from 'store-service'
export StoreModule {
state: ()=> ({
result: {}
}),
actions: {
fetchData({commit}) {
const { result, loading, error } = apolloQueryService()
commit('setState', result);
}
},
mutations: {
setState(state, result): {
state.result = result
}
}
}
The Test:
// store-module.spec.ts
import { StoreModule } from store-module.ts
const store = StoreModule
describe('store-module.ts', () => {
beforeEach(() => {
jest.mock('store-service', () => ({
apolloQueryService: jest.fn().mockReturnValue({
result: { value: 'foo' }, loading: false, error: {}
})
}))
})
test('action', async ()=> {
const commit = jest.fn();
await store.actions.fetchData({ commit });
expect(commit).toHaveBeenCalledWith('setData', { value: 'foo' });
})
}
The test fails, because the commit gets called with ('setData', { value: undefined }) which is the result from the original apolloQueryService. My Mock doesn't seem to work. Am I doing something wrong? Appreciate any help, thanks!
Try this :
// store-module.spec.ts
import { StoreModule } from store-module.ts
// first mock the module. use the absolute path to store-service.ts from the project root
jest.mock('store-service');
// then you import the mocked module.
import { apolloQueryService } from 'store-service';
// finally, you add the mock return values for the mock module
apolloQueryService.mockReturnValue({
result: { value: 'foo' }, loading: false, error: {}
});
/* if the import order above creates a problem for you,
you can extract the first step (jest.mock) to an external setup file.
You should do this if you are supposed to mock it in all tests anyway.
https://jestjs.io/docs/configuration#setupfiles-array */
const store = StoreModule
describe('store-module.ts', () => {
test('action', async ()=> {
const commit = jest.fn();
await store.actions.fetchData({ commit });
expect(commit).toHaveBeenCalledWith('setData', { value: 'foo' });
})
}

mocking setInterval in created hook (vue.js)

I am trying to mock a setInterval inside my created hook but no matter what I try
the function is never called. What I have done so far is using jest.useFakeTimers and inside
each test I would use jest.advanceTimersByTime(8000) to check if my api is being called.
I would appreciate any opinions/help. thanks
my vue file
created() {
setInterval(() => this.checkStatus(), 8000)
},
methods: {
async checkStatus() {
let activated = false
if (!this.isLoading) {
this.isLoading = true
let res = await this.$UserApi.getUserActivateStatus(this.accountId)
this.isLoading = false
if (res.success) {
activated = res.activated
}
if (activated) {
console.log("activated")
} else {
console.log("error")
}
}
}
}
my test file
import { shallowMount, config } from "#vue/test-utils"
import Step4 from "../../../login/smart_station/step4"
describe("Step4", () => {
let wrapper
const $route = {
query: {
account_id: "99"
}
}
const mockGetUserActivateStatus = jest.fn(() =>
Promise.resolve({ success: true, activated: true })
)
beforeEach(() => {
wrapper = shallowMount(Step4, {
mocks: {
$UserApi: {
getUserActivateStatus: mockGetUserActivateStatus
}
}
})
jest.useFakeTimers()
})
it("activates status every 8secs", async () => {
jest.advanceTimersByTime(9000)
expect(mockGetUserActivateStatus).toHaveBeenCalled()
})
})
Jest's Timer Mocks replace the native timer functions like setInterval with their own versions that can be controlled.
Your problem is that you are telling Jest to replace these functions after your component is created and mounted. Since you're using setInterval within your component's created hook, this will still be using the real version.
Move the jest.useFakeTimers() to the top of the beforeEach setup function
beforeEach(() => {
jest.useFakeTimers()
wrapper = shallowMount(Step4, {
mocks: {
$UserApi: {
getUserActivateStatus: mockGetUserActivateStatus
}
}
})
})

How do I test a watcher on a tool that was imported in my component?

I use an instance of a class as a tool in one of my components. This component watches for changes in the class instance. However I fail at writing a test for that watcher.
I tried using jest.fn, spyOn and a setData, but none of these worked.
The class looks like this:
export default class myTool {
constructor () {
this._myData = null
}
get myData () {
return this._myData
}
set myData (updatedMyData) {
this._myData = updatedMyData
}
}
And the component:
import myTool from '#/utils/myTool'
export default {
...
data() {
return {
myTool: null
}
},
methods: {
handleMyDataUpdate(updatedMyData) {
// do something
}
},
mounted() {
this.$watch('myTool.myData', (updatedMyData) => {
this.handleMyDataUpdate(updatedMyData)
})
this.myTool = new myTool()
}
...
}
1st attempt with jest.fn:
test:
it('should call handleMyDataUpdate on myData update.', () => {
const wrapper = mountComponent()
const handleMyDataUpdate = jest.fn()
wrapper.setMethods({ handleMyDataUpdate })
wrapper.vm.myTool.myData = 5
expect(handleMyDataUpdate).toBeCalled()
})
2nd attempt with spyOn:
test:
it('should call handleMyDataUpdate on myData update.', () => {
const wrapper = mountComponent()
const spy = jest.spyOn(wrapper.vm, 'handleMyDataUpdate')
wrapper.vm.myTool.myData = 5
expect(spy).toBeCalled();
}
3rd attempt with setData:
test:
it('should call handleMyDataUpdate on myData update.', () => {
const wrapper = mountComponent()
const handleMyDataUpdate = jest.fn()
wrapper.setMethods({ handleMyDataUpdate })
wrapper.setData({
myTool: {
myData: 5
}
})
expect(handleMyDataUpdate).toBeCalled()
}
Result: the 3 things I tried always fail with the following reason: Expected mock function to have been called., whether I comment the line where myData is updated or not.
Other things that I tried:
I tried wrapping the expect line within a $nextTick, but it doesn't work either:
wrapper.vm.$nextTick(() => {
// expectation
done()
})
The following error outputs and the test is always considered as "passed", whereas it should be "failed":
console.error node_modules/vue/dist/vue.runtime.common.js:1739
{ Error: expect(jest.fn()).toBeCalled()
Looking at line 1739 of vue.runtime.common.js didn't help.
So how do I do to test my watcher?
The issue is your _myData in the myTool class is initially undefined, so it's not reactive. To resolve the issue, initialize _myData in myTool's constructor:
class myTool {
constructor() {
this._myData = null
}
// ...
}
Then, your "1st attempt" test should pass successfully.
demo

Mock Native Module Jest

In my React-Native application i wanna write some unit tests for my Native Libraries.
dataStorage.js
import RNDataStorage, {ACCESSIBLE} from "react-native-data-storage";
const dataStorage = {
setData: function (key, value) {
return RNDataStorage.set(key, value, {accessible: ACCESSIBLE.ALWAYS_THIS_DEVICE_ONLY})
.then(res => {
console.log(res);
return true;
})
},
}
export default dataStorage;
dataStorage.test.js
import dataStorage from '../../src/services/dataStorage'
jest.mock('react-native-data-storage', () => {
return {
RNDataStorage: {
set: jest.fn(),
}
};
});
it('Should return Access & RefreshToken', function () {
dataStorage.setData('John', 'Test');
});
When i run this setup i receive the error: TypeError: Cannot read property 'set' of undefined.
What is the correct way to mocks some modules? Thanks for any help
The module you are mocking is an ES6 module with a default export and a named export.
Mocking it like this should get your test running:
jest.mock('react-native-data-storage', () => {
return {
__esModule: true,
default: {
set: jest.fn(() => Promise.resolve('the response'))
},
ACCESSIBLE: {
ALWAYS_THIS_DEVICE_ONLY: true
}
};
});
Answer based on this post