简体   繁体   中英

nuxt3: how to test SSR page with form, useFetch() and pinia?

In my Nuxt3 project, I have a very basic login page which is SSR like the following:

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

  1. First, I try to test it like a SPA page:
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`
    });
});

Got error:

FAIL tests/pages/login.spec.js > login page > store tokens ReferenceError: document is not defined 文档未定义

  1. Then, I followed the Nuxt3 testing
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'
            }
        });
        
    });
});

But wrapper there is just a jsdom document instance, it can't act like a Vue component.


I wonder:

  1. How to test the user input events?
  2. How to test the code in resovle of useFetch() (in the example, it's the code handling data with pinia)

same question in GitHub

I would unit test the component, so check if inputs work as expected and also if the correct action is triggered on submit. So don't render a whole page, just mount the component in the test.

I would test the login action afterwards separately meaning you mock the data from the API (token, user) and check if they are set correctly to the auth . Plus, if there's a redirect. This should be possible.

You want to test the whole feature (login) which is often referred as "feature testing". But the base is unit tests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM