使用 Mirage 在 Vue Test Utils 中模拟网络请求

使用你的 Mirage 服务器,通过 Vue Test Utils 在不同的服务器场景下测试你的 Vue 应用程序。

这是针对已经在 Vue 应用程序中使用 Vue Test Utils 的用户的快速入门指南。

步骤 1:安装 Mirage

首先,确保你已安装 Mirage

# Using npm
npm install --save-dev miragejs

# Using Yarn
yarn add --dev miragejs

步骤 2:定义你的服务器

创建一个新的 server.js 文件并定义你的模拟服务器。

以下是一个基本示例

// src/server.js
import { createServer, Model } from "miragejs"

export function makeServer({ environment = "development" } = {}) {
  let server = createServer({
    environment,

    models: {
      user: Model,
    },

    seeds(server) {
      server.create("user", { name: "Bob" })
      server.create("user", { name: "Alice" })
    },

    routes() {
      this.namespace = "api"

      this.get("/users", (schema) => {
        return schema.users.all()
      })
    },
  })

  return server
}

在 Vue CLI 中,将此文件放在 src/server.js 中,这样对它的更改就会触发重建。

步骤 3:创建一个使用 Mirage 的测试文件

以下是我们将要测试的 Vue 组件。

<!-- src/App.vue -->
<template>
  <div v-if="serverError" data-testid="server-error">{{ serverError }}</div>

  <div v-else-if="users.length === 0" data-testid="no-users">No users!</div>

  <div v-else>
    <ul id="users">
      <li
        v-for="user in users"
        v-bind:key="user.id"
        :data-testid="'user-' + user.id"
      >
        {{ user.name }}
      </li>
    </ul>
  </div>
</template>

<script>
  export default {
    name: "app",

    data() {
      return {
        users: [],
        serverError: null,
      }
    },

    created() {
      fetch("/api/users")
        .then((res) => res.json())
        .then((json) => {
          if (json.error) {
            this.serverError = json.error
          } else {
            this.users = json.users
          }
        })
    },
  }
</script>

创建一个新的 src/App.spec.js 文件,导入你的 makeServer 函数,并使用 beforeEachafterEach 启动和关闭 Mirage,确保将 test 环境传递给 Mirage

// src/App.spec.js
import { mount } from "@vue/test-utils"
import { makeServer } from "./server"
import App from "./App.vue"

let server

beforeEach(() => {
  server = makeServer({ environment: "test" })
})

afterEach(() => {
  server.shutdown()
})

步骤 4:使用 Mirage 服务器编写测试

使用你的测试为 Mirage 播种不同的数据场景,然后针对 UI 的状态进行断言。

test 环境中,Mirage 不会加载它的数据库 seeds,这样服务器在每次测试运行时都会从空状态开始。

it("shows the users from our server", async () => {
  server.create("user", { id: 1, name: "Luke" })
  server.create("user", { id: 2, name: "Leia" })

  const wrapper = mount(App)

  // let's wait for our vue component to finish loading data
  // we know it's done when the data-testid enters the dom.
  await waitFor(wrapper, '[data-testid="user-1"]')
  await waitFor(wrapper, '[data-testid="user-2"]')

  expect(wrapper.find('[data-testid="user-1"]').text()).toBe("Luke")
  expect(wrapper.find('[data-testid="user-2"]').text()).toBe("Leia")
})

it("shows a message if there are no users", async () => {
  // Don't create any users

  const wrapper = mount(App)
  await waitFor(wrapper, '[data-testid="no-users"]')

  expect(wrapper.find('[data-testid="no-users"]').text()).toBe("No users!")
})

// This helper method returns a promise that resolves
// once the selector enters the wrapper's dom.
const waitFor = function (wrapper, selector) {
  return new Promise((resolve) => {
    const timer = setInterval(() => {
      const userEl = wrapper.findAll(selector)
      if (userEl.length > 0) {
        clearInterval(timer)
        resolve()
      }
    }, 100)
  })
}

步骤 5:修改 Mirage 服务器以测试不同的服务器状态

除了不同的数据场景之外,你还可以使用测试来重新配置 Mirage 服务器以测试新的情况。

例如,你可以像这样测试错误状态

// src/App.spec.js
import { Response } from "miragejs"

it("handles error responses from the server", async () => {
  // Override Mirage's route handler for /users, just for this test
  server.get("/users", () => {
    return new Response(
      500,
      {},
      {
        error: "The database is on vacation.",
      }
    )
  })

  const wrapper = mount(App)

  await waitFor(wrapper, '[data-testid="server-error"]')

  expect(wrapper.find('[data-testid="server-error"]').text()).toBe(
    "The database is on vacation."
  )
})

由于我们使用 beforeEachafterEach 设置 Mirage,因此每个测试都将获得一个基于你的主服务器定义的全新的 Mirage 服务器。你在测试中做出的任何覆盖都会被隔离到该测试中。