Reputation: 1545
I want to test that a BootstrapVue table is rendered correctly based on the data provided by an API. As part of this, I've mocked the fetch
function. When I provide the data statically using the loadItems()
method, it works fine - 3 rows are rendered. But when I instead swap it to using the API calling method getData()
- the rows aren't rendered.
The mocking of fetch
appears to work as the API response is logged successfully, but it doesn't seem to make it to the data option of the Vue component.
The Vue component to test:
// MenuTable.vue
<template>
<div>
<b-table class="table"
:items="items" :fields="fields">
</b-table>
</div>
</template>
<script>
export default {
methods: {
getData() {
fetch('https://www.myexampleapi.com/menu', {
method: 'GET',
mode: 'cors',
})
.then((response) => response.json())
.then((data) => {
console.log(data);
this.items = data;
})
.catch((error) => {
this.error = error.message;
console.log(error);
});
},
loadItems() {
return [
{ cost: 10, food: 'Spaghetti' },
{ cost: 20, food: 'Pizza' },
{ cost: 30, food: 'Hamburger' },
];
},
},
created() {
this.items = this.loadItems(); // load items statically
this.getData(); // load items from API
},
data() {
return {
fields: ['food', 'cost'],
items: [],
};
},
};
</script>
The test file:
// MenuTable.spec.js
import { mount, createLocalVue } from '@vue/test-utils';
import MenuTable from '@/components/MenuTable.vue';
// eslint-disable-next-line no-unused-vars
import { BootstrapVue, BButton, BTable, BRow } from 'bootstrap-vue';
// create an extended `Vue` constructor
const localVue = createLocalVue();
// install plugins as normal
localVue.use(BootstrapVue);
describe('Table.vue Buttons Test', () => {
let wrapper = null;
// SETUP - run before to each unit test
beforeEach(() => {
global.fetch = jest.fn(() => Promise.resolve({
json: () => Promise.resolve([
{ cost: 10, food: 'Spaghetti' },
{ cost: 20, food: 'Pizza' },
{ cost: 30, food: 'Hamburger' },
]),
}));
// render the component
wrapper = mount(MinimalTable, {
localVue,
});
});
// TEARDOWN - run after to each unit test
afterEach(() => {
jest.resetModules();
jest.clearAllMocks();
jest.restoreAllMocks();
wrapper.destroy();
});
it('renders three rows', () => {
const tableComponent = wrapper.findAll('tbody > tr');
console.log(tableComponent.length);
expect(tableComponent.length).toEqual(3);
});
});
I've made sure it's not a case of shallow mounting by using mount
instead, and I think I've made sure that the test awaits a response from the API response by using Promises.
How come the API response data can be logged, but not assigned to the items
data variable?
Upvotes: 1
Views: 793
Reputation: 138696
It seems you're expecting Jest to automatically await the Promise
s, but you actually have to do that explicitly. You can wait until the next macro tick when the fetch
's Promise
s resolve by awaiting a setTimeout()
without a specified delay:
it('renders three rows', async () => {
// wait macro tick when `fetch` Promises resolve
await new Promise(r => setTimeout(r))
const tableComponent = wrapper.findAll('tbody > tr');
console.log(tableComponent.length);
expect(tableComponent.length).toEqual(3);
})
Upvotes: 2