首页 > 解决方案 > 在单元测试中使用模拟获取响应时,Vue 组件无法呈现

问题描述

我想根据 API 提供的数据测试 BootstrapVue 表是否正确呈现。作为其中的一部分,我模拟了这个fetch函数。当我使用该方法静态提供数据时loadItems(),它工作正常 - 呈现 3 行。但是当我改为使用 API 调用方法时getData()- 不会呈现行。

当 API 响应被成功记录时,模拟fetch似乎可以工作,但它似乎并没有出现在 Vue 组件的数据选项中。

要测试的 Vue 组件:

// 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>

测试文件:

// 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);
  });
});

我已经确保这不是通过使用而不是浅安装mount的情况,并且我认为我已经确保测试通过使用 Promises 等待来自 API 响应的响应。

为什么 API 响应数据可以被记录,但不能分配给itemsdata 变量?

标签: vue.jsjestjsmockingfetch-apibootstrap-vue

解决方案


您似乎希望 Jest 自动等待Promises,但实际上您必须明确地这样做。您可以通过等待 a而没有指定的延迟,等到 s 解析时的下一个宏滴答fetchPromisesetTimeout()

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

推荐阅读