diff --git a/docs/.vitepress/config/index.mts b/docs/.vitepress/config/index.mts index e3fe97898..6bdada4b2 100644 --- a/docs/.vitepress/config/index.mts +++ b/docs/.vitepress/config/index.mts @@ -3,6 +3,7 @@ import { frConfig } from './fr.mts' import { zhConfig } from './zh.mts' import { sharedConfig } from './shared.mts' import { defineConfig } from 'vitepress' +import { ruConfig } from './ru.mts' export default defineConfig({ ...sharedConfig, @@ -10,6 +11,13 @@ export default defineConfig({ locales: { root: { label: 'English', lang: 'en-US', link: '/', ...enConfig }, fr: { label: 'Français', lang: 'fr-FR', link: '/fr/', ...frConfig }, - zh: { label: '简体中文 (校对中)', lang: 'zh-CN', link: '/zh/', ...zhConfig } - } + zh: { + label: '简体中文 (校对中)', + lang: 'zh-CN', + link: '/zh/', + ...zhConfig + }, + ru: { label: 'Русский', lang: 'ru-RU', link: '/ru/', ...ruConfig } + }, + }) diff --git a/docs/.vitepress/config/ru.mts b/docs/.vitepress/config/ru.mts new file mode 100644 index 000000000..c61e9d266 --- /dev/null +++ b/docs/.vitepress/config/ru.mts @@ -0,0 +1,128 @@ +import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress' +export const META_URL = '' +export const META_TITLE = 'Vue Test Utils' +export const META_DESCRIPTION = 'Официальный набор инструментов тестирования для Vue.js 3' + +export const ruConfig: LocaleSpecificConfig = { + description: META_DESCRIPTION, + head: [ + ['meta', { property: 'og:url', content: META_URL }], + ['meta', { property: 'og:title', content: META_TITLE }], + ['meta', { property: 'og:description', content: META_DESCRIPTION }], + ['meta', { property: 'twitter:url', content: META_URL }], + ['meta', { property: 'twitter:title', content: META_TITLE }], + ['meta', { property: 'twitter:description', content: META_DESCRIPTION }] + ], + themeConfig: { + docFooter: { + prev: 'Предыдущая', + next: 'Следующая', + }, + outlineTitle: "Содержание", + editLink: { + pattern: 'https://github.com/vuejs/test-utils/edit/main/docs/:path', + text: 'Предложить перевод страницы на GitHub' + }, + nav: [ + { text: 'Руководство', link: '/ru/guide/' }, + { text: 'API', link: '/ru/api/' }, + { text: 'Миграция с Vue 2', link: '/ru/migration/' }, + { + text: 'Changelog', + link: 'https://github.com/vuejs/test-utils/releases' + } + ], + sidebar: { + '/': [ + { + text: 'Установка', + link: '/ru/installation/' + }, + { + text: 'Основы', + items: [ + { text: 'Приступая к изучению', link: '/ru/guide/' }, + { + text: 'Ускоренный курс', + link: '/ru/guide/essentials/a-crash-course' + }, + { + text: 'Условная отрисовка', + link: '/ru/guide/essentials/conditional-rendering' + }, + { + text: 'Тестирование генерации событий', + link: '/ru/guide/essentials/event-handling' + }, + { text: 'Тестирование форм', link: '/ru/guide/essentials/forms' }, + { + text: 'Передача данных в компоненты', + link: '/ru/guide/essentials/passing-data' + }, + { + text: 'Пишем компоненты для легкого тестирования', + link: '/ru/guide/essentials/easy-to-test' + } + ] + }, + { + text: 'Углубленно', + items: [ + { text: 'Слоты', link: '/ru/guide/advanced/slots' }, + { + text: 'Асинхронное поведение', + link: '/ru/guide/advanced/async-suspense' + }, + { + text: 'Выполнение HTTP запросов', + link: '/ru/guide/advanced/http-requests' + }, + { text: 'Transitions', link: '/ru/guide/advanced/transitions' }, + { + text: 'Экземпляр компонента', + link: '/ru/guide/advanced/component-instance' + }, + { + text: 'Переиспользование и композиция', + link: '/ru/guide/advanced/reusability-composition' + }, + { text: 'Тестирование v-model', link: '/ru/guide/advanced/v-model' }, + { text: 'Тестирование Vuex', link: '/ru/guide/advanced/vuex' }, + { text: 'Тестирование Vue Router', link: '/ru/guide/advanced/vue-router' }, + { text: 'Тестирование Teleport', link: '/ru/guide/advanced/teleport' }, + { + text: 'Заглушки и неглубокий Mount', + link: '/ru/guide/advanced/stubs-shallow-mount' + }, + { + text: 'Тестирование Server-side Rendering', + link: '/ru/guide/advanced/ssr' + } + ] + }, + { + text: 'Дополнительные темы', + items: [ + { text: 'Плагины', link: '/ru/guide/extending-vtu/plugins' }, + { + text: 'Сообщество и обучение', + link: '/ru/guide/extending-vtu/community-learning' + } + ] + }, + { + text: 'Ответы на вопросы', + link: '/ru/guide/faq/' + }, + { + text: 'Миграция с Vue 2', + link: '/ru/migration/' + }, + { + text: 'API руководство', + link: '/ru/api/' + } + ] + } + } +} diff --git a/docs/.vitepress/theme/index.mts b/docs/.vitepress/theme/index.mts index 30162d817..b3cf94124 100644 --- a/docs/.vitepress/theme/index.mts +++ b/docs/.vitepress/theme/index.mts @@ -5,7 +5,8 @@ import status from '../translation-status.json' import './custom.css' const i18nLabels = { fr: 'La traduction est synchronisée avec les docs du ${date} dont le hash du commit est ${hash}.', - zh: '该翻译已同步到了 ${date} 的版本,其对应的 commit hash 是 ${hash}
同时该文档仍处于校对中,如有任何疑问或想参与校对工作,请移步这里了解更多。' + zh: '该翻译已同步到了 ${date} 的版本,其对应的 commit hash 是 ${hash}
同时该文档仍处于校对中,如有任何疑问或想参与校对工作,请移步这里了解更多。', + ru: "Последняя дата обновления документации: ${date}" } diff --git a/docs/.vitepress/translation-status.json b/docs/.vitepress/translation-status.json index b7a6d4c97..05c9fedaf 100644 --- a/docs/.vitepress/translation-status.json +++ b/docs/.vitepress/translation-status.json @@ -6,5 +6,9 @@ "zh": { "hash": "7c55128", "date": "2024-11-28" + }, + "ru": { + "hash": "96ef276", + "date": "2024-12-09" } } \ No newline at end of file diff --git a/docs/ru/api/index.md b/docs/ru/api/index.md new file mode 100644 index 000000000..4dbafbd50 --- /dev/null +++ b/docs/ru/api/index.md @@ -0,0 +1,2043 @@ +--- +sidebar: auto +--- + +# API Reference + +## mount + +Создает оболочку, которая содержит смонтированный и отрисованный Vue компонент для тестирования. +Обратите внимание, что при имитации даты/таймеров при помощи Vitest, он должен быть вызван после `vi.setSystemTime`. + +**Сигнатура:** + +```ts +interface MountingOptions { + attachTo?: Element | string + attrs?: Record + data?: () => {} extends Data ? any : Data extends object ? Partial : any + props?: (RawProps & Props) | ({} extends Props ? null : never) + slots?: { [key: string]: Slot } & { default?: Slot } + global?: GlobalMountOptions + shallow?: boolean +} + +function mount(Component, options?: MountingOptions): VueWrapper +``` + +**Подробности:** + +`mount` - это главный метод, предоставляемый Vue Test Utils. Он создает Vue 3 приложение, которое содержит и отрисовывает компонент для тестирования. В свою очередь, он создает оболочку для взаимодействия и проверки компонента. + +```js +import { mount } from '@vue/test-utils' + +const Component = { + template: '
Hello world
' +} + +test('mounts a component', () => { + const wrapper = mount(Component, {}) + + expect(wrapper.html()).toContain('Hello world') +}) +``` + +Обратите внимание, что `mount` принимает второй параметр, чтобы определить конфигурацию состояния компонента. + +**Пример: монтирование вместе с `props` компонента и Vue App плагина** + +```js +const wrapper = mount(Component, { + props: { + msg: 'world' + }, + global: { + plugins: [vuex] + } +}) +``` + +#### options.global + +В зависимости от состояния компонента вы можете настроить вышеупомянутое Vue 3 приложение при помощи [`MountingOptions.global` свойства конфига.](#global) Это было бы полезно для предоставления имитируемых данных, которые, как ожидается, будут доступны вашему компоненту. + +::: tip +Если вы решили настроить общую конфигурацию для многих ваших тестов, тогда вы можете установить конфигурацию для всех ваших тестов, используя экспортированный [`config` объект.](#config) +::: + +### attachTo + +Определяет элемент, на который будет монтироваться компонент. Метод недоступен при использовании `renderToString`. + +**Сигнатура:** + +```ts +attachTo?: Element | string +``` + +**Подробности:** + +Может быть корректным CSS селектором или [`Element`](https://developer.mozilla.org/en-US/docs/Web/API/Element), связанного с документом. + +Обратите внимание, что компонент добавлен к узлу, и метод не заменяет все содержимое узла. Если вы монтируете компонент на тот же самый узел в нескольких тестах, убедитесь, что отмонтировали его после каждого теста при помощи вызова `wrapper.unmount()`, он удалит отрисованные элементы. + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +document.body.innerHTML = ` +
+

Non Vue app

+
+
+` + +test('mounts on a specific element', () => { + const wrapper = mount(Component, { + attachTo: document.getElementById('app') + }) + + expect(document.body.innerHTML).toBe(` +
+

Non Vue app

+

Vue Component

+
+`) +}) +``` + +### attrs + +Устанавливает HTML атрибуты для компонента. + +**Сигнатура:** + +```ts +attrs?: Record +``` + +**Подробности:** + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('attrs', () => { + const wrapper = mount(Component, { + attrs: { + id: 'hello', + disabled: true + } + }) + + expect(wrapper.attributes()).toEqual({ + disabled: 'true', + id: 'hello' + }) +}) +``` + +Обратите внимание, что установка `props` имеет больший приоритет, чем атрибут с тем же названием: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('attribute is overridden by a prop with the same name', () => { + const wrapper = mount(Component, { + props: { + message: 'Hello World' + }, + attrs: { + message: 'this will get overridden' + } + }) + + expect(wrapper.props()).toEqual({ message: 'Hello World' }) + expect(wrapper.attributes()).toEqual({}) +}) +``` + +### data + +Переопределяет `data` компонента. Должно быть функцией: + +**Сигнатура:** + +```ts +data?: () => {} extends Data ? any : Data extends object ? Partial : any +``` + +**Подробности:** + +`Component.vue` + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('data', () => { + const wrapper = mount(Component, { + data() { + return { + message: 'world' + } + } + }) + + expect(wrapper.html()).toContain('Hello world') +}) +``` + +### props + +Устанавливает `props` на компонент при монтировании. + +**Сигнатура:** + +```ts +props?: (RawProps & Props) | ({} extends Props ? null : never) +``` + +**Подробности:** + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('props', () => { + const wrapper = mount(Component, { + props: { + count: 5 + } + }) + + expect(wrapper.html()).toContain('Count: 5') +}) +``` + +### slots + +Устанавливает значения для слотов у компонента. + +**Сигнатура:** + +```ts +type Slot = VNode | string | { render: Function } | Function | Component + +slots?: { [key: string]: Slot } & { default?: Slot } +``` + +**Подробности:** + +Слоты могут быть строкой или любым валидным определением компонента(импортированным из `.vue` файла или предоставленным в inline виде). + +`Component.vue`: + +```vue + +``` + +`Bar.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { h } from 'vue'; +import { mount } from '@vue/test-utils' +import Component from './Component.vue' +import Bar from './Bar.vue' + +test('renders slots content', () => { + const wrapper = mount(Component, { + slots: { + default: 'Default', + first: h('h1', {}, 'Named Slot'), + second: Bar + } + }) + + expect(wrapper.html()).toBe('

Named Slot

Default
Bar
') +}) +``` + +### global + +**Сигнатура:** + +```ts +type GlobalMountOptions = { + plugins?: (Plugin | [Plugin, ...any[]])[] + config?: Partial> + mixins?: ComponentOptions[] + mocks?: Record + provide?: Record + components?: Record + directives?: Record + stubs?: Stubs = Record | Array + renderStubDefaultSlot?: boolean +} +``` + +Вы можете настроить все `global` опции как для каждого теста, так и для всего набора тестов. [Смотрите здесь как настроить сразу все тесты по умолчанию](#config-global). + +#### global.components + +Регистрирует компоненты глобально для монтированного компонента. + +**Сигнатура:** + +```ts +components?: Record +``` + +**Подробности:** + +`Component.vue`: + +```vue + + + +``` + +`GlobalComponent.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import GlobalComponent from '@/components/GlobalComponent' +import Component from './Component.vue' + +test('global.components', () => { + const wrapper = mount(Component, { + global: { + components: { + GlobalComponent + } + } + }) + + expect(wrapper.find('.global-component').exists()).toBe(true) +}) +``` + +#### global.config + +Настраивает [глобальную конфигурацию Vue приложения](https://v3.vuejs.org/api/application-config.html#application-config). + +**Сигнатура:** + +```ts +config?: Partial> +``` + +#### global.directives + +Регистрирует [директиву](https://v3.vuejs.org/api/directives.html#directives) глобально для смонтированного компонента. + +**Сигнатура:** + +```ts +directives?: Record +``` + +**Подробности:** + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' + +import Directive from '@/directives/Directive' + +const Component = { + template: '
Foo
' +} + +test('global.directives', () => { + const wrapper = mount(Component, { + global: { + directives: { + Bar: Directive // Bar matches v-bar + } + } + }) +}) +``` + +#### global.mixins + +Регистрирует [mixin](https://v3.vuejs.org/guide/mixins.html) глобально для монтированного компонента. + +**Сигнатура:** + +```ts +mixins?: ComponentOptions[] +``` + +**Подробности:** + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('global.mixins', () => { + const wrapper = mount(Component, { + global: { + mixins: [mixin] + } + }) +}) +``` + +#### global.mocks + +Имитирует свойство глобального экземпляра. Может быть использовано для имитации `this.$store`, `this.$router` и т.д. + +**Сигнатура:** + +```ts +mocks?: Record +``` + +**Подробности:** + +::: warning +Он предоставляет имитацию переменных, добавленных с помощью сторонних плагинов, но не собственные свойства Vue, такие как $root, $children и т.д. +::: + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('global.mocks', async () => { + const $store = { + dispatch: jest.fn() + } + + const wrapper = mount(Component, { + global: { + mocks: { + $store + } + } + }) + + await wrapper.find('button').trigger('click') + + expect($store.dispatch).toHaveBeenCalledWith('click') +}) +``` + +#### global.plugins + +Устанавливает плагины на монтированный компонент. + +**Сигнатура:** + +```ts +plugins?: (Plugin | [Plugin, ...any[]])[] +``` + +**Подробности:** + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +import myPlugin from '@/plugins/myPlugin' + +test('global.plugins', () => { + mount(Component, { + global: { + plugins: [myPlugin] + } + }) +}) +``` + +Чтобы использовать плагин вместе с опциями, массив опций может быть передан. + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('global.plugins with options', () => { + mount(Component, { + global: { + plugins: [Plugin, [PluginWithOptions, 'argument 1', 'another argument']] + } + }) +}) +``` + +#### global.provide + +Предоставляет данные, которые будут предоставлены в `setup` функции через `inject`. + +**Сигнатура:** + +```ts +provide?: Record +``` + +**Подробности:** + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('global.provide', () => { + const wrapper = mount(Component, { + global: { + provide: { + Theme: 'dark' + } + } + }) + + console.log(wrapper.html()) //=>
Theme is dark
+}) +``` + +Если вы используете ES6 `Symbol` для ключа в provide, вы можете использовать это как динамический ключ: + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +const ThemeSymbol = Symbol() + +mount(Component, { + global: { + provide: { + [ThemeSymbol]: 'value' + } + } +}) +``` + +#### global.renderStubDefaultSlot + +Отрисовывает `default` содерижмое слота, даже при использовании `shallow` или `shallowMount`. + +**Сигнатура:** + +```ts +renderStubDefaultSlot?: boolean +``` + +**Подробности:** + +По умолчанию **false**. + +`Component.vue` + +```vue + + + +``` + +`AnotherComponent.vue` + +```vue + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('global.renderStubDefaultSlot', () => { + const wrapper = mount(ComponentWithSlots, { + slots: { + default: '
My slot content
' + }, + shallow: true, + global: { + renderStubDefaultSlot: true + } + }) + + expect(wrapper.html()).toBe( + '
My slot content
' + ) +}) +``` + +Из-за технических ограничений **это поведение не может быть расширено на слоты, отличные от слотов по умолчанию**. + +#### global.stubs + +Устанавливает глобальную заглушку на смонтированный компонент. + +**Сигнатура:** + +```ts +stubs?: Record +``` + +**Подробности:** + +Заглушка стоит для `Transition` и `TransitionGroup` по умолчанию. + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('global.stubs using array syntax', () => { + const wrapper = mount(Component, { + global: { + stubs: ['Foo'] + } + }) + + expect(wrapper.html()).toEqual('
') +}) + +test('global.stubs using object syntax', () => { + const wrapper = mount(Component, { + global: { + stubs: { Foo: true } + } + }) + + expect(wrapper.html()).toEqual('
') +}) + +test('global.stubs using a custom component', () => { + const CustomStub = { + name: 'CustomStub', + template: '

custom stub content

' + } + + const wrapper = mount(Component, { + global: { + stubs: { Foo: CustomStub } + } + }) + + expect(wrapper.html()).toEqual('

custom stub content

') +}) +``` + +### shallow + +Заглушка для всех дочерних компонентов из компонента. + +**Сигнатура:** + +```ts +shallow?: boolean +``` + +**Подробности:** + +По умолчанию **false**. + +`Component.vue` + +```vue + + + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('shallow', () => { + const wrapper = mount(Component, { shallow: true }) + + expect(wrapper.html()).toEqual( + `` + ) +}) +``` + +::: tip +`shallowMount()` это псевдоним для монтирования компонента при помощи `shallow: true`. +::: + +## Wrapper методы + +Когда вы используете `mount`, `VueWrapper` возвращается с рядом полезных функций для тестирования. `VueWrapper` - это небольшая оболочка вокруг вашего экземпляра компонента. + +Обратите внимание, что методы, такие как `find`, возвращают `DOMWrapper`, который является небольшой оболочкой вокруг DOM элементов в вашем компоненте и его детей. Оба реализуют схожий API. + +### attributes + +Возвращает атрибуты DOM элемента. + +**Сигнатура:** + +```ts +attributes(): { [key: string]: string } +attributes(key: string): string +attributes(key?: string): { [key: string]: string } | string +``` + +**Подробности:** + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('attributes', () => { + const wrapper = mount(Component) + + expect(wrapper.attributes('id')).toBe('foo') + expect(wrapper.attributes('class')).toBe('bar') +}) +``` + +### classes + +**Сигнатура:** + +```ts +classes(): string[] +classes(className: string): boolean +classes(className?: string): string[] | boolean +``` + +**Подробности:** + +Возвращает массив классов элемента. + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('classes', () => { + const wrapper = mount(Component) + + expect(wrapper.classes()).toContain('my-span') + expect(wrapper.classes('my-span')).toBe(true) + expect(wrapper.classes('not-existing')).toBe(false) +}) +``` + +### emitted + +Возвращает все сгенерированные события из вашего компонента. + +**Сигнатура:** + +```ts +emitted(): Record +emitted(eventName: string): undefined | T[] +emitted(eventName?: string): undefined | T[] | Record +``` + +**Подробности:** + +Аргументы хранятся в массиве, поэтому вы можете проверить, какие аргументы были сгенерированы вместе с каждым событием. + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('emitted', () => { + const wrapper = mount(Component) + + // wrapper.emitted() вернет { greet: [ ['hello'], ['goodbye'] ] } + + expect(wrapper.emitted()).toHaveProperty('greet') + expect(wrapper.emitted().greet).toHaveLength(2) + expect(wrapper.emitted().greet[0]).toEqual(['hello']) + expect(wrapper.emitted().greet[1]).toEqual(['goodbye']) +}) +``` + +### exists + +Проверяет, существует ли элемент или нет. + +**Сигнатура:** + +```ts +exists(): boolean +``` + +**Подробности:** + +Вы можете использовать тот же синтаксис по аналогии с `querySelector` + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('exists', () => { + const wrapper = mount(Component) + + expect(wrapper.find('span').exists()).toBe(true) + expect(wrapper.find('p').exists()).toBe(false) +}) +``` + +### find + +Находит элемент и возвращает `DOMWrapper`, если он найден. + +**Сигнатура:** + +```ts +find(selector: K): DOMWrapper +find(selector: K): DOMWrapper +find(selector: string): DOMWrapper +find(selector: string): DOMWrapper +find(selector: string | RefSelector): DOMWrapper; +``` + +**Подробности:** + +Вы можете использовать такой же синтаксис, как и с `querySelector`. `find` - это, по сути, псевдоним для `querySelector`. В дополнении, вы можете найти ref элемента. + +Он похож на `get`, но `find` вернет ErrorWrapper, если элемент не найден, но [`get`](#get) выбросит ошибку. + +Как правило, всегда используйте `find`, когда вы проверяете что-то, что не существует. Если вы проверяете что-то, что существует, используйте [`get`](#get). + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('find', () => { + const wrapper = mount(Component) + + wrapper.find('span') //=> найдено; вернет DOMWrapper + wrapper.find('[data-test="span"]') //=> найдено; вернет DOMWrapper + wrapper.find({ ref: 'span' }) //=> найдено; вернет DOMWrapper + wrapper.find('p') //=> ничего не найдено; вернет ErrorWrapper +}) +``` + +### findAll + +Похож на `find`, но вместо этого возвращает массив `DOMWrapper`. + +**Сигнатура:** + +```ts +findAll(selector: K): DOMWrapper[] +findAll(selector: K): DOMWrapper[] +findAll(selector: string): DOMWrapper[] +findAll(selector: string): DOMWrapper[] +``` + +**Подробности:** + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import BaseTable from './BaseTable.vue' + +test('findAll', () => { + const wrapper = mount(BaseTable) + + // .findAll() вернет массив DOMWrappers + const thirdRow = wrapper.findAll('span')[2] +}) +``` + +### findComponent + +Находит экземпляр Vue компонента и вернет `VueWrapper`, если найден. В противном случае вернет `ErrorWrapper`. + +**Сигнатура:** + +```ts +findComponent(selector: string): WrapperLike +findComponent(selector: T | Exclude): VueWrapper> +findComponent(selector: T | string): DOMWrapper +findComponent(selector: NameSelector | RefSelector): VueWrapper +findComponent(selector: T | FindComponentSelector): VueWrapper +findComponent(selector: FindComponentSelector): WrapperLike +``` + +**Подробности:** + +`findComponent` поддерживает несколько вариантов: + +| синтаксис | пример | детали | +| -------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| querySelector | `findComponent('.component')` | Соответствует стандартному селектору запросов (query selector). | +| Component name | `findComponent({name: 'a'})` | Соответствует PascalCase, snake-case, camelCase | +| Component ref | `findComponent({ref: 'ref'})` | Может использоваться только для прямых ссылок на дочерние элементы смонтированного компонента (т.е. ref должен находится на дочернем компоненте, а не внутри него) | +| SFC | `findComponent(Component)` | Передать импортированный компонент напрямую | + +`Foo.vue` + +```vue + + + +``` + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +import Foo from '@/Foo.vue' + +test('findComponent', () => { + const wrapper = mount(Component) + + // Все следующие запросы вернули бы VueWrapper + + wrapper.findComponent('.foo') + wrapper.findComponent('[data-test="foo"]') + + wrapper.findComponent({ name: 'Foo' }) + + wrapper.findComponent({ ref: 'foo' }) + + wrapper.findComponent(Foo) +}) +``` + +:::warning +Если `ref` в компоненте ссылается на HTML элемент, `findComponent` вернет пустую оболочку. Это ожидаемое поведение. +::: + +:::warning Использование с CSS селекторами +Использование `findComponent` с CSS селекторами может привести к запутанному поведению + +Рассмотрите этот пример: + +```js +const ChildComponent = { + name: 'Child', + template: '
' +} +const RootComponent = { + name: 'Root', + components: { ChildComponent }, + template: '' +} +const wrapper = mount(RootComponent) +const rootByCss = wrapper.findComponent('.root') // => нашел Root компонент +expect(rootByCss.vm.$options.name).toBe('Root') +const childByCss = wrapper.findComponent('.child') +expect(childByCss.vm.$options.name).toBe('Root') // => все еще Root компонент +``` + +Причина такого поведения в том, что `RootComponent` и `ChildComponent` используют одинаковый DOM узел, и только первый соответствующий компонент включен для каждого уникального DOM узла +::: + +:::info WrapperLike тип при использовании CSS селектора +Для примера, при использовании `wrapper.findComponent('.foo')`, VTU вернет `WrapperLike` тип. Дело в том, что функциональному компоненту мог бы потребоваться +`DOMWrapper`, иначе `VueWrapper`. Вы можете заставить вернуть `VueWrapper`, указав правильный тип компонента: + +```typescript +wrapper.findComponent('.foo') // вернет WrapperLike +wrapper.findComponent('.foo') // вернет VueWrapper +wrapper.findComponent('.foo') // вернет VueWrapper +``` +::: + +### findAllComponents + +**Сигнатура:** + +```ts +findAllComponents(selector: string): WrapperLike[] +findAllComponents(selector: T | Exclude): VueWrapper>[] +findAllComponents(selector: string): DOMWrapper[] +findAllComponents(selector: T): DOMWrapper[] +findAllComponents(selector: NameSelector): VueWrapper[] +findAllComponents(selector: T | FindAllComponentsSelector): VueWrapper[] +findAllComponents(selector: FindAllComponentsSelector): WrapperLike[] +``` + +**Подробности:** + +Похож на `findComponent`, но находит все экземпляры Vue компонентов, который совпадают с селектором. Вернет массив `VueWrapper`. + +:::warning +`ref` синтаксис не поддерживается в `findAllComponents`. Все остальные синтаксисы запросов будут работать. +::: + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('findAllComponents', () => { + const wrapper = mount(Component) + + // Вернет массив VueWrapper + wrapper.findAllComponents('[data-test="number"]') +}) +``` + +:::warning Использование с CSS селекторами +`findAllComponents` имеет одинаковое поведение при использовании с CSS селектором, как [findComponent](#findcomponent) +::: + +### get + +Получит элемент и вернет `DOMWrapper`, если найден. В противном случае выбросит ошибку. + +**Сигнатура:** + +```ts +get(selector: K): Omit, 'exists'> +get(selector: K): Omit, 'exists'> +get(selector: string): Omit, 'exists'> +get(selector: string): Omit, 'exists'> +``` + +**Подробности:** + +Он похож на `find`, но `get` выбросит ошибку, если элемент не найден, в то время как [`find`](#find) вернет ErrorWrapper. + +Как правило, всегда используйте `get`, исключая, когда вы проверяете что-то, что не существует. В этом случае используйте [`find`](#find). + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('get', () => { + const wrapper = mount(Component) + + wrapper.get('span') //=> найден; вернет DOMWrapper + + expect(() => wrapper.get('.not-there')).toThrowError() +}) +``` + +### getComponent + +Получит экземпляр Vue компонента и вернет `VueWrapper`, если найден. Иначе он выбросит ошибку. + +**Сигнатура:** + +```ts +getComponent(selector: new () => T): Omit, 'exists'> +getComponent(selector: { name: string } | { ref: string } | string): Omit, 'exists'> +getComponent(selector: any): Omit, 'exists'> +``` + +**Подробности:** + +Он похож на `findComponent`, но `getComponent`выбросит ошибку, если экземпляр Vue компонента не найден, в том время как [`findComponent`](#findComponent) вернет ErrorWrapper. + +**Поддерживаемый синтаксис:** + +| синтаксис | пример | детали | +| -------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| querySelector | `getComponent('.component')` | Соответствует стандартному селектору запросов. | +| Component name | `getComponent({name: 'a'})` | Соответствует PascalCase, snake-case, camelCase | +| Component ref | `getComponent({ref: 'ref'})` | Может использоваться только для прямых ссылок на дочерние элементы смонтированного компонента (т.е. ref должен находится на дочернем компоненте, а не внутри него) | +| SFC | `getComponent(Component)` | Передать импортированный компонент напрямую | + +`Foo.vue` + +```vue + + + +``` + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +import Foo from '@/Foo.vue' + +test('getComponent', () => { + const wrapper = mount(Component) + + wrapper.getComponent({ name: 'foo' }) // вернет VueWrapper + wrapper.getComponent(Foo) // вернет VueWrapper + + expect(() => wrapper.getComponent('.not-there')).toThrowError() +}) +``` + +### html + +Вернет HTML элемента. + +По умолчанию результат форматируется при помощи [`js-beautify`](https://github.com/beautify-web/js-beautify), чтобы сделать снапшоты более читабельными. Используйте `raw: true` опцию, чтобы получить неформатированную html строку. + +**Сигнатура:** + +```ts +html(): string +html(options?: { raw?: boolean }): string +``` + +**Подробности:** + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('html', () => { + const wrapper = mount(Component) + + expect(wrapper.html()).toBe( + '
\n' + + '

Hello world

\n' + + '
' + ) + + expect(wrapper.html({ raw: true })).toBe('

Hello world

') +}) +``` + +### isVisible + +Проверяет является ли элемент видимым или нет. + +**Сигнатура:** + +```ts +isVisible(): boolean +``` + +**Подробности:** + +::: warning +`isVisible()` работает корректно, только если оболочка прикреплена к DOM, используя [`attachTo`](#attachTo) +::: + +```js +const Component = { + template: `
` +} + +test('isVisible', () => { + const wrapper = mount(Component, { + attachTo: document.body + }); + + expect(wrapper.find('span').isVisible()).toBe(false); +}) +``` + +### props + +Возвращает `props`, переданные в Vue компонент. + +**Сигнатура:** + +```ts +props(): { [key: string]: any } +props(selector: string): any +props(selector?: string): { [key: string]: any } | any +``` + +**Подробности:** + +`Component.vue`: + +```js +export default { + name: 'Component', + props: { + truthy: Boolean, + object: Object, + string: String + } +} +``` + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('props', () => { + const wrapper = mount(Component, { + global: { stubs: ['Foo'] } + }) + + const foo = wrapper.getComponent({ name: 'Foo' }) + + expect(foo.props('truthy')).toBe(true) + expect(foo.props('object')).toEqual({}) + expect(foo.props('notExisting')).toEqual(undefined) + expect(foo.props()).toEqual({ + truthy: true, + object: {}, + string: 'string' + }) +}) +``` + +:::tip +Как правило, проверяйте влияние переданного `prop` (DOM обновление, сгенерированное событие и так далее). Это сделает тесты более мощными, чем просто проверка того, что `prop` был передан. +::: + +### setData + +Обновляет внутреннее свойство `data` у компонента. + +**Сигнатура:** + +```ts +setData(data: Record): Promise +``` + +**Подробности:** + +`setData` не позволяет установить новые поля, которые не были определены в компоненте. + +::: warning +А также, обратите внимание, что`setData` не изменяет composition API `setup()` данные. +::: + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('setData', async () => { + const wrapper = mount(Component) + expect(wrapper.html()).toContain('Count: 0') + + await wrapper.setData({ count: 1 }) + + expect(wrapper.html()).toContain('Count: 1') +}) +``` + +::: warning +Вы должны использовать `await`, когда вызываете `setData`, чтобы убедиться в том, что Vue обновит DOM до того, как тест продолжится. +::: + +### setProps + +Обновляет `props` компонента. + +**Сигнатура:** + +```ts +setProps(props: Record): Promise +``` + +**Подробности:** + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('updates prop', async () => { + const wrapper = mount(Component, { + props: { + message: 'hello' + } + }) + + expect(wrapper.html()).toContain('hello') + + await wrapper.setProps({ message: 'goodbye' }) + + expect(wrapper.html()).toContain('goodbye') +}) +``` + +::: warning +Вы должны использовать `await`, когда вызываете `setProps`, чтобы убедиться в том, что Vue обновит DOM до того, как тест продолжится. +::: + +### setValue + +Устанавливает значение на DOM элементе. Включая: + +- `` + - `type="checkbox"` и `type="radio"` обрабатываются и установится в `element.checked`. +- `