[Vue Unit tesing] Testing API Calls (mocking)

In this lesson, we will be learning how to mock REST API calls. Mocking is a technique used in software testing to simulate the behavior of objects or systems that the software being tested depends on. This is done to isolate the software being tested from the variables outside of its control, such as network connections or external services.

Mocking is important in testing because it allows developers to test their code more thoroughly and efficiently. By creating mock objects or services, developers can test their code in isolation, without having to worry about the behavior of external dependencies.

📂src/components/PostCard.vue

<template>
  <div>
    <div v-if="post">
      <h1 data-testid="post-title">{{ post.title }}</h1>
      <p data-testid="post-body">{{ post.body }}</p>
    </div>
    <p v-if="loading" data-testid="loader">Loading...</p>
    <p v-if="error" data-testid="error-message">{{ error }}</p>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import axios from "axios";

const post = ref(null);
const loading = ref(true);
const error = ref(null);

const fetchPost = async () => {
  try {
    const { data } = await axios.get(
      "https://jsonplaceholder.typicode.com/posts/1"
    );
    post.value = data;
  } catch (err) {
    error.value = err.message;
  } finally {
    loading.value = false;
  }
};

onMounted(() => {
  fetchPost();
});

</script>

 

What we’ll be testing

Before we get started, let’s decide on what we’ll be testing.

  1. First, we want to make sure that our app successfully makes an API request and displays the correct data if the request is successful.
  2. Next, we want to test that our app properly handles errors by displaying an error message if the API request fails.

 

Before we mount our app, we need to be able to intercept the GET request made using Axios and return a mocked value. We do this because we don’t want to make an actual request to the real API server. Remember, mocks allow us to test in isolation.

To do this, we can use the spyOn function from Vitest. Vitest provides utility functions to help you with this through its vi helper. You can import { vi } from 'vitest' or access it globally when the Vitest global configuration is enabled.

Let’s configure it globally. This way, we can use functions (such as describeexpect and test) from Vitest without having to import them every single time.

In your Vitest config file set globals to true:

📃 vitest.config.js

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true,
  },
})

 

📁src/components/tests/PostCard.test.js

import axios from 'axios'
import PostCard from '../PostCard.vue'
import { mount, flushPromises } from '@vue/test-utils'

const mockPost = {
  userId: 1,
  id: 1,
  title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
  body: 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'
}

describe('Post Card Component', () => {
  test('can fetch and display a post', async () => {
    vi.spyOn(axios, 'get').mockResolvedValueOnce({ data: mockPost })

    const wrapper = mount(PostCard)

    expect(wrapper.html()).toContain('Loading...')

    await flushPromises()

    // new
    expect(wrapper.find('[data-testid="post-title"]').text()).toBe(mockPost.title)

    expect(wrapper.find('[data-testid="post-body"]').text()).toBe(mockPost.body)
  })

  test('can display an error message if fetching a post fails', async () => {
    vi.spyOn(axios, 'get').mockRejectedValueOnce(new Error('Error occurred'))

    const wrapper = mount(PostCard)

    expect(wrapper.html()).toContain('Loading...')

    await flushPromises()

    expect(wrapper.find('[data-testid="error-message"]').text()).toBe('Error occurred')
  })
})

Since the process of fetching our post is asynchronous, we need to ensure that the promise operation has been completed before writing our assertion.

To do this, we make use of flushPromises, a utility method from Vue test utils that flushes all pending resolved promise handlers. You can await the call of flushPromises to flush pending promises and improve the readability of your test.

 

posted @   Zhentiw  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2022-11-30 [Typescript 4.9] Satisfies operator
2022-11-30 [Typescript 4.9] Auto-Accessors in Classes
2022-11-30 [Typescript 4.9] 'in' operator
2022-11-30 [Typescript] 122. Hard - Mutable Keys
2022-11-30 [XState] Invoke actor
2022-11-30 [XState] Create Actor in Vanilla Javascript
2020-11-30 [Java spring] Building a command-line application
点击右上角即可分享
微信分享提示