nuxt3:如何使用 form、useFetch() 和 pinia 测试 SSR 页面?

Den*_*han 7 vue.js nuxt.js nuxtjs3 vitest

在我的 Nuxt3 项目中,我有一个非常基本的登录页面,它是 SSR,如下所示:

页面/login.vue

<template>
    <form
        @submit.prevent="login">
        <input
            name="email"
            v-model="form.email"/>
        <input
            name="password"
            v-model="form.password"/>
        <button>login</button>
    <form>
</template>

<script setup>
import { useAuth } from '~/store/auth.js'; 

const auth = useAuth();
const form = ref({email: '', password: ''});
const router = useRouter();

const login = async () => {
    useFetch('/api/auth/tokens', {
        method: 'POST',
        body: form.value
    })
    .then(({ data }) => {
          const { token, user } =  data.value;
          auth.setUser(user);
          auth.setToken(token);
          router.push('/profile');           
    })
}
</script>
Run Code Online (Sandbox Code Playgroud)
  1. 首先,我尝试像 SPA 页面一样测试它:
import { describe, test, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import LoginPage from '~/pages/login.vue';

describe('login page', async () => {

    test('store tokens', async () => {

        const wrapper = mount(LoginPage);

        const email = 'test@example.com';
        const password = 'password';

        await wrapper.find('[name="email"]').setValue(email);
        await wrapper.find('[name="password"]').setValue(password);

        await wrapper.find('form').trigger('submit.prevent');

        expect(
            wrapper.emitted('submit')[0][0]
        ).toStrictEqual({
            email,
            password,
        });

        // But this does not test the code in `then()` which handled the response and redirect to `/profile`
    });
});
Run Code Online (Sandbox Code Playgroud)

出现错误:

失败测试/页面/login.spec.js>登录页面>存储令牌ReferenceError:文档未定义 文档未定义

  1. 然后,我按照Nuxt3测试
import { describe, test, expect } from 'vitest';
import { setup, $fetch } from '@nuxt/test-utils';
import { JSDOM } from 'jsdom';

describe('login page', async () => {

    await setup();

    test('store tokens', async () => {

        const wrapper = (new JSDOM(await $fetch('/login'))).window.document;

        const email = 'test@example.com';
        const password = 'password';

        await wrapper.find('[name="email"]').setValue(email);
        await wrapper.find('[name="password"]').setValue(password);

        await wrapper.find('form').trigger('submit.prevent');

        expect($fetch).toHaveBeenCalledWith('/api/auth/tokens', {
            method: 'POST',
            body: {
                email: 'test@example.com',
                password: 'password'
            }
        });
        
    });
});
Run Code Online (Sandbox Code Playgroud)

wrapper只有一个 jsdom 文档实例,它不能像 Vue 组件一样工作。


我想知道:

  1. 如何测试用户输入事件?
  2. 如何测试resovleof中的代码useFetch()(示例中是用pinia处理数据的代码)

GitHub上有同样的问题

小智 1

我将对组件进行单元测试,因此检查输入是否按预期工作,以及提交时是否触发了正确的操作。所以不要渲染整个页面,只需在测试中挂载组件即可。

之后我会单独测试该login操作,这意味着您模拟来自 API(令牌、用户)的数据,并检查它们是否正确设置为auth. 另外,如果有重定向。这应该是可能的。

您想要测试整个功能(登录),这通常称为“功能测试”。但基础是单元测试。