Оригинальная статья: Daniel Kuroski — Working an application in Vue.js with TDD — An extensive guide for people who have time — part 2
Это вторая часть в серии статей:
В прошлой статье я кратко рассказал о проекте, объяснил некоторые концепции и мы написали наш первый тест. Теперь мы можем перейти к одной из самых интересных частей этой серии, на мой взгляд, и, вероятно, это самая короткая статья.
Теперь, когда мы уже проверили, выполняет ли наш компонент рендеринг, давайте проверим, правильно ли он его выполняет. В этом случае мы хотим гарантировать, что в нем есть компоненты VUserSearchForm и VUserProfile.
import { shallowMount } from '@vue/test-utils' import UserView from '@/views/UserView' import VUserSearchForm from '@/components/VUserSearchForm' import VUserProfile from '@/components/VUserProfile' describe('UserView', () => { it('renders the component', () => { // arrange const wrapper = shallowMount(UserView) // assert expect(wrapper.html()).toMatchSnapshot() }) it('renders main child components', () => { // arrange const wrapper = shallowMount(UserView) const userSearchForm = wrapper.find(VUserSearchForm) const userProfile = wrapper.find(VUserProfile) // assert expect(userSearchForm.exists()).toBe(true) expect(userProfile.exists()).toBe(true) }) })
В этом втором тесте мы делаем следующее:
Опять же, тесты не должны быт успешными, так как ни один из вышеупомянутых компонентов не существует.
Давайте исправим это … нам нужно только создать их и сослаться на них в нашем UserView
src/components/VUserProfile.vue
<script> export default { name: 'UserProfile' } </script> <template> <div> UserProfile </div> </template>
src/components/VUserSearchForm.vue
<script> export default { name: 'UserSearchForm' } </script> <template> <div> UserSearchForm </div> </template>
src/views/UserView.vue
<script> import VUserSearchForm from '@/components/VUserSearchForm' import VUserProfile from '@/components/VUserProfile' export default { name: 'UserView', components: { VUserSearchForm, VUserProfile, } } </script> <template> <div> <VUserSearchForm /> <VUserProfile /> </div> </template>
Сейчас наш тест стал успешно проходить. Нам нужно только обновить наш Snapshot. Нажмите u на терминале.
Некоторые люди могут сказать, что этот тест в конечном итоге лишает смысла наличие первого, который мы сделали ранее, но здесь мы проверяем только наличие основных компонентов. Нам не нужно делать этот тест ВСЕМ нашим дочерним компонентам, если у нас есть h1 или p или любой другой элемент, который не является «жизненно важным» для работы нашего компонента. Snapshot будет достаточно, и он также гарантирует любое текстовое изменение, будь то изменение класса или свойства. Тогда оба теста полезны и важны.
Используя тот факт, что мы завершили ЗЕЛЕНЫЙ этап, мы можем перейти к следующему этапу, реорганизовать наши тесты. Если вы заметили, у нас есть несколько повторений. Теперь я собираюсь предложить изменение структуры, чтобы использовать форму, которую я применяю ко всем своим приложениям.
Изменения в UserView.spec.js
import { shallowMount } from '@vue/test-utils' import UserView from '@/views/UserView' import VUserSearchForm from '@/components/VUserSearchForm' import VUserProfile from '@/components/VUserProfile' describe('UserView', () => { const build = () => { const wrapper = shallowMount(UserView) return { wrapper, userSearchForm: () => wrapper.find(VUserSearchForm), userProfile: () => wrapper.find(VUserProfile) } } it('renders the component', () => { // arrange const { wrapper } = build() // assert expect(wrapper.html()).toMatchSnapshot() }) it('renders main child components', () => { // arrange const { userSearchForm, userProfile } = build() // assert expect(userSearchForm().exists()).toBe(true) expect(userProfile().exists()).toBe(true) }) })
Стоит подчеркнуть, что эти селекторы являются функциями, и это важно, так как мы хотим контролировать момент поиска элемента.
Если мы не будем использовать функции, с момента вызова build будет немедленно вызван wrapper.find.
В этот момент функция build может не иметь особого смысла, и некоторые люди скажут: «Почему вы не создаете эти структуры в beforeEach»! Но поверьте мне, по мере развития, в этом будет больше смысла.
В третьем тесте мы можем проверить привязки компонента. Давайте посмотрим, передает ли оно свойство для компонента VUserProfile, содержащего объект. Этот объект будет иметь всю информацию исследуемого пользователя.
import { shallowMount } from '@vue/test-utils' import UserView from '@/views/UserView' import VUserSearchForm from '@/components/VUserSearchForm' import VUserProfile from '@/components/VUserProfile' describe('UserView', () => { const build = () => { const wrapper = shallowMount(UserView, { data: () => ({ user: {} }) }) return { wrapper, userSearchForm: () => wrapper.find(VUserSearchForm), userProfile: () => wrapper.find(VUserProfile) } } ... ... it('passes a binded user prop to user profile component', () => { // arrange const { wrapper, userProfile } = build() wrapper.setData({ user: { name: 'Daniel' } }) // assert expect(userProfile().vm.user).toBe(wrapper.vm.user) }) })
Здесь я хочу подчеркнуть, что не буду обсуждать, является ли это интеграционным или унитарным тестом. Во всей серии статей у нас будут унитарные тесты.
Для простоты теста, только в строке 9, я передал свойств data нашему компоненту, содержащему нашего пользователя Github.
В строке 27 я назначаю значение этого объекта {name: ‘Daniel’}, а затем проверяю, получил ли наш компонент VUserProfile того же пользователя в качестве props.
Теперь, когда наши тесты снова не проходят, давайте починим их, не забывая обновлять наши Snapshot.
Файл UserView.vue
<script> import VUserSearchForm from '@/components/VUserSearchForm' import VUserProfile from '@/components/VUserProfile' export default { name: 'UserView', components: { VUserSearchForm, VUserProfile, }, data() { return { user: { name: '' } } } } </script> <template> <div> <VUserSearchForm /> <VUserProfile :user="user" /> </div> </template>
Только вставки свойства не достаточно. Нам нужно поместить это объявление в наш VUserProfile.
<script> export default { name: 'UserProfile', props: { user: { type: Object, required: true, default: () => ({}) } } } </script> <template> <div> UserProfile </div> </template>
Здесь мы гарантируем, что наш UserView.vue передает желаемое свойство для VUserProfile.vue.
Используя тот факт, что мы находимся на зеленом этапе, мы можем думать, что в этом случае было бы совершенно нормально сохранить состояние нашего приложения внутри UserView.vue. Но для демонстрационных проблем скажем, что этот пользователь Github, используется в других местах нашего приложения.
Далее мы собираемся отправить этого пользователя в наше хранилище и проверить, отправляем ли мы user в store вместо свойства data.
В этой статье мы сделали:
Далее, мы завершим наш компонент с интеграцией с хранилищем.
Следующая часть
Твиттер автора оригинальной статьи : @DKuroski
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…
View Comments
При прогоне последнего теста
Не вернет объект, чтобы тесты прошли нужно заменить: