I am using Vue's composition API and importing a module into a single-file component. I assign the return value of the module to a variable within the setup method and then return the value so the template can consume the variable. The component renders one ItemComponent for each item recieved from the imported module.
The actual application is working fine and renders the correct amount of items. My test, on the other hand, is failing, and it appears the mockReturnValue function is not getting invoked.
Single-File Component Code
<template>
<ul class="ItemList">
<ItemComponent
v-for="item in items"
:key="item.id"
:item="item" />
</ul>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import ItemComponent from '@/components/ItemComponent.vue';
import module from '@/module';
export default defineComponent({
components: {
ItemComponent,
},
setup() {
const { items } = module.property // note destructuring here
console.log(items);
return { items };
},
});
</script>
mock-module.ts
export const property = {
items: jest.fn(),
};
(mock) index.ts
import {module} from './modules/mock-module';
export default {module}
Test file
import module from '@/modules/__mocks__/index.ts';
jest.mock('../../../src/modules/index.ts');
it('should render an ItemComponent for each item', () => {
module.property.items.mockReturnValue([{}, {}, {}]); // Doesn't seem to get invoked?
const wrapper = mount(MyComponent, { shallow: true });
expect(wrapper.findAllComponents('item-component-stub').length)
.toBe(3);
});
Result
The test fails and finds 0 items, and when I console.log(items)
from within the single-file component, I get the following:
[Function: mockConstructor] {
_isMockFunction: true,
getMockImplementation: [Function (anonymous)],
mock: [Getter/Setter],
mockClear: [Function (anonymous)],
mockReset: [Function (anonymous)],
mockRestore: [Function (anonymous)],
mockReturnValueOnce: [Function (anonymous)],
mockResolvedValueOnce: [Function (anonymous)],
mockRejectedValueOnce: [Function (anonymous)],
mockReturnValue: [Function (anonymous)],
mockResolvedValue: [Function (anonymous)],
mockRejectedValue: [Function (anonymous)],
mockImplementationOnce: [Function (anonymous)],
mockImplementation: [Function (anonymous)],
mockReturnThis: [Function (anonymous)],
mockName: [Function (anonymous)],
getMockName: [Function (anonymous)]
}
This indicates (to me) that the test is using the mock file, but for some reason, is not invoking the .mockReturnValue()
call. If I simply change the mock dependency from jest.fn() to some actual value, the console.log statement returns that value. Of course, I don't want to do that, as I need to be able to set different return values in different tests.
What I Expect
I would expect when I call module.property.items.mockReturnValue([{}, {}, {}])
that the console.log would print an array with three empty objects, and the test would pass with 3/3 ItemComponents rendered.
items: jest.fn()
makesitems
a spy. Console output is the one that should be expected, it shows that it's a function.mockReturnValue
has no chance to be not invoked if the test continues. Its result can be seen as:Since
items
is supposed to be an array and not a function, it was mocked the wrong way. This is commonly done by mocking properties directly with nojest.mock
performed on this module:It should be additionally guaranteed that changed value won't affect other tests, e.g. by doing this in
jest.isolateModules
to reimport a hierarchy of affected modules.This can be done with Jest spies as well but requires to keep a reference to getter function to access it easily:
And used as:
Also importing directly from
__mocks__
is wrong, mocked module should be imported from its regular location.