Как написать тестовый модуль Jest для компонента формы Vue, который использует хранилище Vuex? - PullRequest
0 голосов
/ 08 мая 2018

У меня есть форма для входа. Когда я заполняю форму входа данными и нажимаю кнопку входа в систему:

  • данные формы (имя пользователя, пароль) отправляются на сервер, и ответ вернулся
  • Если данные формы неверны, компонент <flash-message>
  • Если данные формы верны, пользователь перенаправляется на панель управления

Поскольку этот компонент сильно зависит от хранилища Vuex, я не могу вспомнить некоторые допустимые тестовые случаи для этого компонента.

  • Этот компонент тестируемый?
  • Если тестируется , как мне написать юнит-тест в шутку?
  • Какую часть моего компонента мне надо издеваться?
  • Должен ли я использовать методы mount / shallowMount vue-test-utils для переноса моего компонента?
  • Мой компонент использует компоненты пользовательского интерфейса Bootstrap-Vue. Как с ними бороться?

У меня нет опыта работы с экосистемой JavaScript, поэтому было бы полезно получить подробное объяснение.

Login.vue

<template>
  <b-col sm="6" offset-sm="3">
    <h1><span class="fa fa-sign-in"></span> Login</h1>
    <flash-message></flash-message>
    <!-- LOGIN FORM -->
    <div class="form">
        <b-form-group>
            <label>Email</label>
            <input type="text" class="form-control" name="email" v-model="email">
        </b-form-group>

        <b-form-group>
            <label>Password</label>
            <input type="password" class="form-control" name="password" v-model="password">
        </b-form-group>

        <b-btn type="submit" variant="warning" size="lg" @click="login">Login</b-btn>
    </div>

    <hr>

    <p>Need an account? <b-link :to="{name:'signup'}">Signup</b-link></p>
    <p>Or go <b-link :to="{name:'home'}">home</b-link>.</p>
  </b-col>

</template>

<script>
export default {
  data () {
    return {
      email: '',
      password: ''
    }
  },
  methods: {
    async login () {
      this.$store.dispatch('login', {data: {email: this.email, password: this.password}, $router: this.$router})
    }
  }
}
</script>

1 Ответ

0 голосов
/ 08 мая 2018

Vue Test использует документацию говорит:

[W] мы рекомендуем писать тесты, которые утверждают открытый интерфейс вашего компонента и рассматривают его внутренние компоненты как черный ящик. Один тестовый случай подтвердил бы, что некоторые входные данные (взаимодействие с пользователем или изменение реквизитов), предоставленные компоненту, приводят к ожидаемому выходному результату (результат рендеринга или выданные пользовательские события).

То есть мы не должны тестировать компоненты начальной загрузки, это работа тех, кто сопровождает этот проект.

Написать код с учетом модульных тестов

Чтобы упростить тестирование компонентов, поможет определить их ответственность. Это означает, что форма входа должна быть собственной SFC (компонент с одним файлом), а страница входа - это другая SFC, которая использует форму входа.

Здесь у нас есть форма входа, изолированная от страницы входа.

<template>
    <div class="form">
        <b-form-group>
            <label>Email</label>
            <input type="text" class="form-control" 
                   name="email" v-model="email">
        </b-form-group>

        <b-form-group>
            <label>Password</label>
            <input type="password" class="form-control" 
                   name="password" v-model="password">
        </b-form-group>

        <b-btn type="submit" variant="warning" 
               size="lg" @click="login">
               Login
        </b-btn>
    </div>
</template>

<script>
export default {
    data() {
        return { email: '', password: '' };
    },
    methods: {
        login() {
            this.$store.dispatch('login', {
                email: this.email,
                password: this.password
            }).then(() => { /* success */ }, () => { /* failure */ });
        }
    }
}
</script>

Я удалил маршрутизатор из хранилища действий хранилища, поскольку хранилище не несет ответственности за обработку перенаправления при успешном входе или неудаче входа в систему. Магазин не должен знать, что перед ним есть фронтенд. Он имеет дело с данными и асинхронными запросами, связанными с данными.

Проверьте каждую часть независимо

Проверьте действия магазина индивидуально. Затем их можно полностью смоделировать в компонентах.

Тестирование действий магазина

Здесь мы хотим убедиться, что магазин делает то, что должен. Таким образом, мы можем проверить, что состояние имеет правильные данные, что HTTP-вызовы выполняются при их издевательстве.

import Vuex from 'vuex';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import storeConfig from '@/store/config';

describe('actions', () => {
    let http;
    let store;

    beforeAll(() => {
        http = new MockAdapter(axios);
        store = new Vuex.Store(storeConfig());
    });

    afterEach(() => {
        http.reset();
    });

    afterAll(() => {
        http.restore();
    });

    it('calls login and sets the flash messages', () => {
        const fakeData = { /* ... */ };
        http.onPost('api/login').reply(200, { data: fakeData });
        return store.dispatch('login')
            .then(() => expect(store.state.messages).toHaveLength(1));
    });
    // etc.
});

Тестирование нашей простой LoginForm

Единственная реальная вещь, которую делает этот компонент, - отправка действия login при вызове кнопки отправки. Поэтому мы должны проверить это. Нам не нужно проверять само действие, поскольку оно уже проверено индивидуально.

import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils';
import LoginForm from '@/components/LoginForm';

const localVue = createLocalVue();
localVue.use(Vuex);

describe('Login form', () => {

    it('calls the login action correctly', () => {
        const loginMock = jest.fn(() => Promise.resolve());
        const store = new Vuex.Store({
            actions: {
                // mock function
                login: loginMock
            }
        });
        const wrapper = mount(LoginForm, { localVue, store });
        wrapper.find('button').trigger('click');
        expect(loginMock).toHaveBeenCalled();
    });
});

Проверка компонента флеш-сообщения

В том же духе мы должны смоделировать состояние хранилища с помощью введенных сообщений и убедиться, что компонент FlashMessage правильно отображает сообщения, проверив наличие элементов каждого сообщения, классов и т. Д.

Тестирование страницы входа

Компонент страницы входа теперь может быть просто контейнером, поэтому тестировать особо нечего.

<template>
    <b-col sm="6" offset-sm="3">
        <h1><span class="fa fa-sign-in"></span> Login</h1>
        <flash-message />
        <!-- LOGIN FORM -->
        <login-form />
        <hr>
        <login-nav />
    </b-col>
</template>

<script>
import FlashMessage from '@/components/FlashMessage';
import LoginForm from '@/components/LoginForm';
import LoginNav from '@/components/LoginNav';

export default {
    components: {
        FlashMessage,
        LoginForm,
        LoginNav,
    }
}
</script>

Когда использовать mount против shallow

Документация по shallow гласит:

Как и mount, он создает Wrapper, который содержит смонтированный и визуализированный компонент Vue, но с заглушенными дочерними компонентами.

Это означает, что дочерние компоненты из компонента контейнера будут заменены <!-- --> комментариями, и вся их интерактивность будет отсутствовать. Таким образом, он изолирует тестируемый компонент от всех требований, которые могут иметь его дочерние элементы.

Вставленный DOM страницы входа в систему будет почти пустым, где будут заменены компоненты FlashMessage, LoginForm и LoginNav:

<b-col sm="6" offset-sm="3">
    <h1><span class="fa fa-sign-in"></span> Login</h1>
    <!-- -->
    <!-- LOGIN FORM -->
    <!-- -->
    <hr>
    <!-- -->
</b-col>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...