JavaScript

Создание приложения на Vue.js по TDD – обширное руководство для людей, у которых есть время – часть 5

Spread the love

Оригинальная статья: Daniel KuroskiWorking an application in Vue.js with TDD — An extensive guide for people who have time — part 4

Это четвертая часть в серии статей:

В предыдущей статье мы закончили наше приложение 👏

В этой статье мы рассмотрим, как интегрировать наше приложение со сторонней библиотекой и как обновить наши тесты, чтобы справиться с этим изменением.

Улучшение внешнего вида + сторонние библиотеки

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

Мы можем скачать его через Vue CLI. Давайте загрузим и установим его вручную

npm i -d element-ui

Далее давайте установим его в нашем проекте.

src/main.js

import Vue from 'vue'
import Element from 'element-ui'
import App from './App.vue'
import router from './router'
import store from './store'
import './registerServiceWorker'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(Element)

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

Вставьте следующую разметку в App.vue

<template>
  <el-container>
    <el-main>
      <router-view/>
    </el-main>
  </el-container>
</template>

Наши тесты все еще проходят, и мы можем перейти к изменениям компонентов.

src/components/VUserSearchForm.vue

<script>
export default {
  name: 'UserSearchForm',
  data() {
    return {
      username: ''
    }
  }
}
</script>

<template>
  <form @submit.prevent="$emit('submitted', username)">
    <el-input
      placeholder="Pesquise o usuário"
      v-model="username"
      class="search-form__input"
    >
      <el-button
        class="search-form__button"
        native-type="submit"
        slot="append"
        icon="el-icon-search"
      ></el-button>
    </el-input>
  </form>
</template>

Здесь мы только что провели наш первый большой рефакторинг, касающийся внешнего вида. По сути, у нас есть новый макет для формы нашего приложения:

Потрясающе! Наша форма выглядит лучше, но:

RED

Наши тесты не проходят. Но что именно здесь происходит?

Что ж… поскольку мы загрузили ElementUI как стороннюю зависимость и загрузили ее в main.js, когда мы используем элементы внутри тестов нашего компонента VUserSearchForm.vue, наш компонент, используемый в тесте, не знает о ElementUI , поэтому нам нужно вернуться к файлу тестов и сделать именно то, что мы делали на main.js.

tests/unit/VUserSearchForm.spec.js

import { shallowMount, mount, createLocalVue } from '@vue/test-utils'
import ElementUI from 'element-ui'
import VUserSearchForm from '@/components/VUserSearchForm'

const localVue = createLocalVue()
localVue.use(ElementUI)

describe('VUserSearchForm', () => {
  const build = () => {
    const wrapper = shallowMount(VUserSearchForm, { localVue })

    return {
      wrapper,
      input: () => wrapper.find('input'),
      button: () => wrapper.find('button'),
    }
  }
  ...
  ...

Отлично. Мы вставляем сюда зависимость createLocalVue в строке 1, а также импортируем ElementUI в строке 2.

После этого мы создаем локальный экземпляр, подключаем ElementUI и добавляем локальный экземпляр localVue в качестве опции, когда мы визуализируем наш компонент в строке 10. По сути, это то же самое, что мы делали в Vuexcase 😄

Теперь нужно только обновить snapshot, и у нас будет более краткая информация об ошибках:

RED

Здесь нам нужно только обновить ссылки на наши селекторы для поиска классов HTML.

const build = () => {
  const wrapper = shallowMount(VUserSearchForm, { localVue })return {
    wrapper,
    input: () => wrapper.find('.search-form__input'),
    button: () => wrapper.find('.search-form__button'),
  }
}

Теперь проходит входной тест, а тест кнопки — нет?

RED

Что происходит, так это то, что мы визуализируем el-input, который является настраиваемым элементом ElementUI, поэтому нам нужно вставить в него нашу кнопку, чтобы отобразить правильный интерфейс. Теперь, чтобы протестировать его, мы должны отобразить дерево зависимостей всех компонентов. Поэтому, мы собираемся использовать mount.

tests/unit/VUserSearchForm.spec.js

import { shallowMount, mount, createLocalVue } from '@vue/test-utils'
import ElementUI from 'element-ui'
import VUserSearchForm from '@/components/VUserSearchForm'

const localVue = createLocalVue()
localVue.use(ElementUI)

describe('VUserSearchForm', () => {
  const build = () => {
    const options = { localVue }
    const wrapper = shallowMount(VUserSearchForm, options)
    const wrapperMounted = mount(VUserSearchForm, options)

    return {
      wrapper,
      wrapperMounted,
      input: () => wrapper.find('.search-form__input'),
      inputMounted: () => wrapperMounted.find('input'),
      button: () => wrapperMounted.find('button'),
    }
  }

Сначала мы импортируем mount. Затем мы создаем wrapperMounting, а затем возвращаем нашу кнопку, используя wrapperMounting. Теперь, когда наш компонент «mounted», мы имеем доступ ко всему дереву нашего компонента. Таким образом, мы можем искать кнопку и даже визуализированный input ElementUI.

В этом случае я также возвращаю wrapperMounting и inputMounting, так как мы собираемся использовать их в следующем тесте.

Далее, мы должны выполнить наш последний тестовый проход, в ходе которого мы проверяем событие submitted.

tests/unit/VUserSearchForm.spec.js

...
...
it('calls "submitted" event when submitting form', () => {
    // arrange
    const expectedUser = 'kuroski'
    const { wrapperMounted, button, inputMounted } = build()
    inputMounted().element.value = expectedUser

    // act
    inputMounted().trigger('input')
    button().trigger('click')
    button().trigger('submit')

    // assert
    expect(wrapperMounted.emitted().submitted[0]).toEqual([expectedUser])
  })
...
...

Для этого, поскольку мы имеем дело с событиями из собственных компонентов, созданных ElementUI, нам нужно импортировать wrapperMounting и inputMounting вместо версий в shallowMount.

Их нужно только заменить на тест. Таким образом, мы возвращаемся к зеленой фазе.

GREEN

Наконец, давайте изменим только css в VUserProfile.vue, так как мы уже изменили один из компонентов для использования сторонней библиотеки.

src/components/VUserProfile.vue

<style scoped>
.user-profile {
  border-top: solid 1px #ccc;
  padding-top: 20px;
  margin-top: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.user-profile__avatar {
  border-radius: 50%;
  width: 150px;
  height: 150px;
}
.user-profile__name {
  margin-top: 14px;
  font-size: 24px;
  font-family: 'Bungee', cursive;
  text-transform: uppercase;
}
.user-profile__bio {
  margin-top: 14px;
  font-family: 'Open Sans', sans-serif;
}
</style>
Finish =D

Теперь все готово! Наше приложение проверено и функционирует 😄


Заключение

В пятой части мы сделали:

  • Подключили сторонние библиотеки компонентов
  • Обновили тесты, чтобы учесть эти изменения

Твиттер автора оригинальной статьи : @DKuroski

Была ли вам полезна эта статья?
[4 / 4.5]

Spread the love
Editorial Team

View Comments

  • Спасибо за перевод!
    Отличный материал, чтобы войти в курс дела тестирования Vue приложений.

    Единственное, метод find у враппера в июле 2020 deprecated. Используем findComponent

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

11 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

11 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago