Skip to content

Commit 56b7334

Browse files
committed
add teleport page
1 parent 935bd04 commit 56b7334

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed

docs/ru/guide/advanced/teleport.md

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# Тестирование Teleport
2+
3+
Vue 3 предоставляет новый встроенный компонент: `<Teleport>`, который позволяет компонентам "телепортировать" их содержимое далеко за пределы их собственного `<template>`. Большинство тестов, написанные при помощи Vue Test Utils, ограничены компонентом, переданным в `mount`, который привносит некоторую сложность, когда нужно протестировать компонент, который телепортирован за пределы компонента, где он был изначально отрисован.
4+
5+
Вот несколько стратегий и техник для тестирования компонентов, используя `<Teleport>`.
6+
7+
::: tip
8+
Если вы хотите протестировать остальную часть вашего компонента, игнорируя `teleport`, вы можете поставить заглушку на `teleport`, передав `teleport: true` в [global stubs option](../../api/#global-stubs).
9+
:::
10+
11+
## Пример
12+
13+
В этом примере мы тестируем `<Navbar>` компонент. Он отрисовывает `<Signup>` компонент внутри `<Teleport>`. `target` атрибут `<Teleport>` - это элемент, расположенный за пределами `<Navbar>` компонента.
14+
15+
Это `Navbar.vue` компонент:
16+
17+
```vue
18+
<template>
19+
<Teleport to="#modal">
20+
<Signup />
21+
</Teleport>
22+
</template>
23+
24+
<script lang="ts">
25+
import { defineComponent } from 'vue'
26+
import Signup from './Signup.vue'
27+
28+
export default defineComponent({
29+
components: {
30+
Signup
31+
}
32+
})
33+
</script>
34+
```
35+
36+
Он просто телепортирует `<Signup>` в другое место. Для целей нашего примера это просто.
37+
38+
`Signup.vue` - это форма, которая проверяет, содержит ли `username` больше чем 8 символов. Если да, то когда форма отправлена, генерируется `signup` событие с `username` в качестве параметра. Протестировать это будет нашей целью.
39+
40+
```vue
41+
<template>
42+
<div>
43+
<form @submit.prevent="submit">
44+
<input v-model="username" />
45+
</form>
46+
</div>
47+
</template>
48+
49+
<script>
50+
export default {
51+
emits: ['signup'],
52+
data() {
53+
return {
54+
username: ''
55+
}
56+
},
57+
computed: {
58+
error() {
59+
return this.username.length < 8
60+
}
61+
},
62+
methods: {
63+
submit() {
64+
if (!this.error) {
65+
this.$emit('signup', this.username)
66+
}
67+
}
68+
}
69+
}
70+
</script>
71+
```
72+
73+
## Создание компонента
74+
75+
Начнем с простого теста:
76+
77+
```ts
78+
import { mount } from '@vue/test-utils'
79+
import Navbar from './Navbar.vue'
80+
import Signup from './Signup.vue'
81+
82+
test('emits a signup event when valid', async () => {
83+
const wrapper = mount(Navbar)
84+
})
85+
```
86+
87+
Запуск этого теста выдаст вам предупреждение: `[Vue warn]: Failed to locate Teleport target with selector "#modal"`. Давайте создадим его:
88+
89+
```ts {5-15}
90+
import { mount } from '@vue/test-utils'
91+
import Navbar from './Navbar.vue'
92+
import Signup from './Signup.vue'
93+
94+
beforeEach(() => {
95+
// создать teleport target
96+
const el = document.createElement('div')
97+
el.id = 'modal'
98+
document.body.appendChild(el)
99+
})
100+
101+
afterEach(() => {
102+
// очистить
103+
document.body.innerHTML = ''
104+
})
105+
106+
test('teleport', async () => {
107+
const wrapper = mount(Navbar)
108+
})
109+
```
110+
111+
Мы используем Jest для этого примера, который не сбрасывает DOM каждый тест. По этой причине желательно очищать DOM после каждого теста при помощи `afterEach`.
112+
113+
## Взаимодействие с телепортированным компонентом
114+
115+
Следующая вещь, которую мы должны сделать, - это заполнить пользовательский input. К несчастью, мы не можем использовать `wrapper.find('input')`. Почему нет? Быстрый `console.log(wrapper.html())` покажет нам:
116+
117+
```html
118+
<!--teleport start-->
119+
<!--teleport end-->
120+
```
121+
122+
Мы видим несколько комментариев, используемых Vue для обработки `<Teleport>`, но без `<input>`. Поскольку `<Signup>` компонент (и его HTML) не отрисован внутри `<Navbar>` где-либо, он был телепортирован за пределы компонента.
123+
124+
Хотя фактический HTML был телепортирован за пределы, оказывается, что Virtual DOM, связанный с `<Navbar>`, поддерживает ссылку на оригинальный компонент. Это значит, что вы можете использовать `getComponent` и `findComponent`, которые работают с Virtual DOM, но не с обычным DOM.
125+
126+
```ts {12}
127+
beforeEach(() => {
128+
// ...
129+
})
130+
131+
afterEach(() => {
132+
// ...
133+
})
134+
135+
test('teleport', async () => {
136+
const wrapper = mount(Navbar)
137+
138+
wrapper.getComponent(Signup) // получен!
139+
})
140+
```
141+
142+
`getComponent` вернет `VueWrapper`. Теперь вы можете использовать методы такие как `get`, `find` и `trigger`.
143+
144+
Давайте закончим тест:
145+
146+
```ts {4-8}
147+
test('teleport', async () => {
148+
const wrapper = mount(Navbar)
149+
150+
const signup = wrapper.getComponent(Signup)
151+
await signup.get('input').setValue('valid_username')
152+
await signup.get('form').trigger('submit.prevent')
153+
154+
expect(signup.emitted().signup[0]).toEqual(['valid_username'])
155+
})
156+
```
157+
158+
Он пройден!
159+
160+
Полный тест:
161+
162+
```ts
163+
import { mount } from '@vue/test-utils'
164+
import Navbar from './Navbar.vue'
165+
import Signup from './Signup.vue'
166+
167+
beforeEach(() => {
168+
// создать teleport target
169+
const el = document.createElement('div')
170+
el.id = 'modal'
171+
document.body.appendChild(el)
172+
})
173+
174+
afterEach(() => {
175+
// очистить
176+
document.body.innerHTML = ''
177+
})
178+
179+
test('teleport', async () => {
180+
const wrapper = mount(Navbar)
181+
182+
const signup = wrapper.getComponent(Signup)
183+
await signup.get('input').setValue('valid_username')
184+
await signup.get('form').trigger('submit.prevent')
185+
186+
expect(signup.emitted().signup[0]).toEqual(['valid_username'])
187+
})
188+
```
189+
190+
Вы можете заглушить `teleport`, используя `teleport: true`:
191+
192+
```ts
193+
import { mount } from '@vue/test-utils'
194+
import Navbar from './Navbar.vue'
195+
196+
test('teleport', async () => {
197+
const wrapper = mount(Navbar, {
198+
global: {
199+
stubs: {
200+
teleport: true
201+
}
202+
}
203+
})
204+
})
205+
```
206+
207+
## Заключение
208+
209+
- Создайте элемент для телепортирования при помощи `document.createElement`.
210+
- Найдите телепортированные компоненты при помощи `getComponent` или `findComponent`, которые работают с Virtual DOM уровнем.

0 commit comments

Comments
 (0)