From 82101986da7a4e30ae0fbdaab6b106880a214500 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 11 Jun 2018 16:49:49 +0300 Subject: [PATCH 01/32] Migrate Russian docs to VuePress --- docs/.vuepress/_redirects | 8 + docs/.vuepress/config.js | 33 ++- docs/ru/README.md | 71 +++++ docs/ru/SUMMARY.md | 66 +++++ docs/ru/api/README.md | 56 ++++ docs/ru/api/components/README.md | 5 + docs/ru/api/components/TransitionGroupStub.md | 31 ++ docs/ru/api/components/TransitionStub.md | 30 ++ docs/ru/api/config.md | 26 ++ docs/ru/api/createLocalVue.md | 27 ++ docs/ru/api/mount.md | 130 +++++++++ docs/ru/api/options.md | 197 +++++++++++++ docs/ru/api/selectors.md | 60 ++++ docs/ru/api/shallow.md | 114 ++++++++ docs/ru/api/wrapper-array/README.md | 12 + docs/ru/api/wrapper-array/at.md | 20 ++ docs/ru/api/wrapper-array/contains.md | 23 ++ docs/ru/api/wrapper-array/destroy.md | 16 ++ docs/ru/api/wrapper-array/is.md | 19 ++ docs/ru/api/wrapper-array/isEmpty.md | 16 ++ docs/ru/api/wrapper-array/isVueInstance.md | 17 ++ docs/ru/api/wrapper-array/setComputed.md | 25 ++ docs/ru/api/wrapper-array/setData.md | 21 ++ docs/ru/api/wrapper-array/setMethods.md | 26 ++ docs/ru/api/wrapper-array/setProps.md | 21 ++ docs/ru/api/wrapper-array/trigger.md | 25 ++ docs/ru/api/wrapper/README.md | 16 ++ docs/ru/api/wrapper/attributes.md | 15 + docs/ru/api/wrapper/classes.md | 17 ++ docs/ru/api/wrapper/contains.md | 22 ++ docs/ru/api/wrapper/destroy.md | 19 ++ docs/ru/api/wrapper/emitted.md | 57 ++++ docs/ru/api/wrapper/emittedByOrder.md | 27 ++ docs/ru/api/wrapper/exists.md | 20 ++ docs/ru/api/wrapper/find.md | 26 ++ docs/ru/api/wrapper/findAll.md | 26 ++ docs/ru/api/wrapper/html.md | 15 + docs/ru/api/wrapper/is.md | 18 ++ docs/ru/api/wrapper/isEmpty.md | 15 + docs/ru/api/wrapper/isVueInstance.md | 15 + docs/ru/api/wrapper/name.md | 17 ++ docs/ru/api/wrapper/props.md | 21 ++ docs/ru/api/wrapper/setData.md | 19 ++ docs/ru/api/wrapper/setMethods.md | 23 ++ docs/ru/api/wrapper/setProps.md | 46 +++ docs/ru/api/wrapper/text.md | 15 + docs/ru/api/wrapper/trigger.md | 44 +++ docs/ru/guides/README.md | 10 + docs/ru/guides/choosing-a-test-runner.md | 46 +++ docs/ru/guides/common-tips.md | 135 +++++++++ docs/ru/guides/dom-events.md | 210 ++++++++++++++ docs/ru/guides/getting-started.md | 144 ++++++++++ docs/ru/guides/testing-SFCs-with-jest.md | 212 ++++++++++++++ .../guides/testing-SFCs-with-mocha-webpack.md | 184 ++++++++++++ docs/ru/guides/testing-async-components.md | 97 +++++++ docs/ru/guides/using-with-vue-router.md | 79 ++++++ docs/ru/guides/using-with-vuex.md | 265 ++++++++++++++++++ 57 files changed, 2968 insertions(+), 2 deletions(-) create mode 100644 docs/ru/README.md create mode 100644 docs/ru/SUMMARY.md create mode 100644 docs/ru/api/README.md create mode 100644 docs/ru/api/components/README.md create mode 100644 docs/ru/api/components/TransitionGroupStub.md create mode 100644 docs/ru/api/components/TransitionStub.md create mode 100644 docs/ru/api/config.md create mode 100644 docs/ru/api/createLocalVue.md create mode 100644 docs/ru/api/mount.md create mode 100644 docs/ru/api/options.md create mode 100644 docs/ru/api/selectors.md create mode 100644 docs/ru/api/shallow.md create mode 100644 docs/ru/api/wrapper-array/README.md create mode 100644 docs/ru/api/wrapper-array/at.md create mode 100644 docs/ru/api/wrapper-array/contains.md create mode 100644 docs/ru/api/wrapper-array/destroy.md create mode 100644 docs/ru/api/wrapper-array/is.md create mode 100644 docs/ru/api/wrapper-array/isEmpty.md create mode 100644 docs/ru/api/wrapper-array/isVueInstance.md create mode 100644 docs/ru/api/wrapper-array/setComputed.md create mode 100644 docs/ru/api/wrapper-array/setData.md create mode 100644 docs/ru/api/wrapper-array/setMethods.md create mode 100644 docs/ru/api/wrapper-array/setProps.md create mode 100644 docs/ru/api/wrapper-array/trigger.md create mode 100644 docs/ru/api/wrapper/README.md create mode 100644 docs/ru/api/wrapper/attributes.md create mode 100644 docs/ru/api/wrapper/classes.md create mode 100644 docs/ru/api/wrapper/contains.md create mode 100644 docs/ru/api/wrapper/destroy.md create mode 100644 docs/ru/api/wrapper/emitted.md create mode 100644 docs/ru/api/wrapper/emittedByOrder.md create mode 100644 docs/ru/api/wrapper/exists.md create mode 100644 docs/ru/api/wrapper/find.md create mode 100644 docs/ru/api/wrapper/findAll.md create mode 100644 docs/ru/api/wrapper/html.md create mode 100644 docs/ru/api/wrapper/is.md create mode 100644 docs/ru/api/wrapper/isEmpty.md create mode 100644 docs/ru/api/wrapper/isVueInstance.md create mode 100644 docs/ru/api/wrapper/name.md create mode 100644 docs/ru/api/wrapper/props.md create mode 100644 docs/ru/api/wrapper/setData.md create mode 100644 docs/ru/api/wrapper/setMethods.md create mode 100644 docs/ru/api/wrapper/setProps.md create mode 100644 docs/ru/api/wrapper/text.md create mode 100644 docs/ru/api/wrapper/trigger.md create mode 100644 docs/ru/guides/README.md create mode 100644 docs/ru/guides/choosing-a-test-runner.md create mode 100644 docs/ru/guides/common-tips.md create mode 100644 docs/ru/guides/dom-events.md create mode 100644 docs/ru/guides/getting-started.md create mode 100644 docs/ru/guides/testing-SFCs-with-jest.md create mode 100644 docs/ru/guides/testing-SFCs-with-mocha-webpack.md create mode 100644 docs/ru/guides/testing-async-components.md create mode 100644 docs/ru/guides/using-with-vue-router.md create mode 100644 docs/ru/guides/using-with-vuex.md diff --git a/docs/.vuepress/_redirects b/docs/.vuepress/_redirects index 86da66f9e..fac8b530f 100644 --- a/docs/.vuepress/_redirects +++ b/docs/.vuepress/_redirects @@ -23,3 +23,11 @@ /zh/api/wrapper/* /zh/api/wrapper.html/#:splat /zh/api/wrapper-array/* /zh/api/wrapper-array.html/#:splat + +/ru/api/mount /ru/api/#mount +/ru/api/shallowMount /ru/api/#shallowmount +/ru/api/createLocalVue /ru/api/#createlocalvue +/ru/api/config /ru/api/#config + +/ru/api/wrapper/* /ru/api/wrapper.html/#:splat +/ru/api/wrapper-array/* /ru/api/wrapper-array.html/#:splat diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 2bfaa5445..8ac01fb68 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -14,6 +14,11 @@ module.exports = { lang: 'zh-CN', title: 'Vue Test Utils', description: '测试 Vue 组件的实用工具' + }, + '/ru/': { + lang: 'ru', + title: 'Vue Test Utils', + description: 'Библиотека для тестирования Vue-компонентов' } }, serviceWorker: true, @@ -93,7 +98,31 @@ module.exports = { '/ja/api/options', '/ja/api/components/' ] - } + }, + '/ru/': { + label: 'Русский', + selectText: 'Переводы', + editLinkText: 'Изменить эту страницу на GitHub', + nav: [ + { + text: 'API', + link: '/ru/api/' + }, + { + text: 'Руководства', + link: '/ru/guides/' + } + ], + sidebar: [ + '/ru/', + '/ru/guides/', + '/ru/api/', + '/ru/api/wrapper/', + '/ru/api/wrapper-array/', + '/ru/api/options', + '/ru/api/components/' + ] + }, } }, markdown: { @@ -102,4 +131,4 @@ module.exports = { md.use(require('markdown-it-include')) } } -} \ No newline at end of file +} diff --git a/docs/ru/README.md b/docs/ru/README.md new file mode 100644 index 000000000..91f9ca68d --- /dev/null +++ b/docs/ru/README.md @@ -0,0 +1,71 @@ +# vue-test-utils + +`vue-test-utils` — официальная библиотека модульного тестирования для Vue.js. + +## Содержание + +* [Руководства](guides/README.md) + * [Введение](guides/getting-started.md) + * [Общие советы](guides/common-tips.md) + * [Мышь, клавиши и другие события DOM](guides/dom-events.md) + * [Чем запускать тесты](guides/choosing-a-test-runner.md) + * [Тестирование однофайловых компонентов с Jest](guides/testing-SFCs-with-jest.md) + * [Тестирование однофайловых компонентов с Mocha + webpack](guides/testing-SFCs-with-mocha-webpack.md) + * [Использование с Vue Router](guides/using-with-vue-router.md) + * [Использование с Vuex](guides/using-with-vuex.md) + * [Тестирование асинхронной логики](guides/testing-async-components.md) +* [API](api/README.md) + * [mount](api/mount.md) + * [shallow](api/shallow.md) + * [Опции монтирования](api/options.md) + - [context](api/options.md#context) + - [slots](api/options.md#slots) + - [stubs](api/options.md#stubs) + - [mocks](api/options.md#mocks) + - [localVue](api/options.md#localvue) + - [attachToDocument](api/options.md#attachtodocument) + - [attrs](api/options.md#attrs) + - [listeners](api/options.md#listeners) + - [provide](api/options.md#provide) + - [другие опции](api/options.md#other-options) + * [Wrapper](api/wrapper/README.md) + * [attributes](api/wrapper/attributes.md) + * [classes](api/wrapper/classes.md) + * [contains](api/wrapper/contains.md) + * [emitted](api/wrapper/emitted.md) + * [emittedByOrder](api/wrapper/emittedByOrder.md) + * [exists](api/wrapper/exists.md) + * [destroy](api/wrapper/destroy.md) + * [find](api/wrapper/find.md) + * [findAll](api/wrapper/findAll.md) + * [html](api/wrapper/html.md) + * [is](api/wrapper/is.md) + * [isEmpty](api/wrapper/isEmpty.md) + * [isVueInstance](api/wrapper/isVueInstance.md) + * [name](api/wrapper/name.md) + * [props](api/wrapper/props.md) + * [setComputed](api/wrapper/setComputed.md) + * [setData](api/wrapper/setData.md) + * [setMethods](api/wrapper/setMethods.md) + * [setProps](api/wrapper/setProps.md) + * [text](api/wrapper/text.md) + * [trigger](api/wrapper/trigger.md) + * [WrapperArray](api/wrapper-array/README.md) + * [at](api/wrapper-array/at.md) + * [contains](api/wrapper-array/contains.md) + * [exists](api/wrapper/exists.md) + * [destroy](api/wrapper-array/destroy.md) + * [is](api/wrapper-array/is.md) + * [isEmpty](api/wrapper-array/isEmpty.md) + * [isVueInstance](api/wrapper-array/isVueInstance.md) + * [setComputed](api/wrapper-array/setComputed.md) + * [setData](api/wrapper-array/setData.md) + * [setMethods](api/wrapper-array/setMethods.md) + * [setProps](api/wrapper-array/setProps.md) + * [trigger](api/wrapper-array/trigger.md) + * [Компоненты](api/components/README.md) + * [TransitionStub](api/components/TransitionStub.md) + * [TransitionGroupStub](api/components/TransitionGroupStub.md) + * [Селекторы](api/selectors.md) + * [createLocalVue](api/createLocalVue.md) + * [Конфигурация](api/config.md) diff --git a/docs/ru/SUMMARY.md b/docs/ru/SUMMARY.md new file mode 100644 index 000000000..bfc5add55 --- /dev/null +++ b/docs/ru/SUMMARY.md @@ -0,0 +1,66 @@ +## Содержание + +* [Руководства](guides/README.md) + * [Введение](guides/getting-started.md) + * [Общие советы](guides/common-tips.md) + * [Мышь, клавиши и другие события DOM](guides/dom-events.md) + * [Чем запускать тесты](guides/choosing-a-test-runner.md) + * [Тестирование однофайловых компонентов с Jest](guides/testing-SFCs-with-jest.md) + * [Тестирование однофайловых компонентов с Mocha + webpack](guides/testing-SFCs-with-mocha-webpack.md) + * [Использование с Vue Router](guides/using-with-vue-router.md) + * [Использование с Vuex](guides/using-with-vuex.md) + * [Тестирование асинхронной логики](guides/testing-async-components.md) +* [API](api/README.md) + * [mount](api/mount.md) + * [shallowMount](api/shallowMount.md) + * [Опции монтирования](api/options.md) + - [context](api/options.md#context) + - [slots](api/options.md#slots) + - [stubs](api/options.md#stubs) + - [mocks](api/options.md#mocks) + - [localVue](api/options.md#localvue) + - [attachToDocument](api/options.md#attachtodocument) + - [attrs](api/options.md#attrs) + - [listeners](api/options.md#listeners) + - [provide](api/options.md#provide) + - [другие опции](api/options.md#other-options) + * [Wrapper](api/wrapper/README.md) + * [attributes](api/wrapper/attributes.md) + * [classes](api/wrapper/classes.md) + * [contains](api/wrapper/contains.md) + * [emitted](api/wrapper/emitted.md) + * [emittedByOrder](api/wrapper/emittedByOrder.md) + * [exists](api/wrapper/exists.md) + * [destroy](api/wrapper/destroy.md) + * [find](api/wrapper/find.md) + * [findAll](api/wrapper/findAll.md) + * [html](api/wrapper/html.md) + * [is](api/wrapper/is.md) + * [isEmpty](api/wrapper/isEmpty.md) + * [isVueInstance](api/wrapper/isVueInstance.md) + * [name](api/wrapper/name.md) + * [props](api/wrapper/props.md) + * [setData](api/wrapper/setData.md) + * [setMethods](api/wrapper/setMethods.md) + * [setProps](api/wrapper/setProps.md) + * [text](api/wrapper/text.md) + * [trigger](api/wrapper/trigger.md) + * [WrapperArray](api/wrapper-array/README.md) + * [at](api/wrapper-array/at.md) + * [contains](api/wrapper-array/contains.md) + * [exists](api/wrapper/exists.md) + * [destroy](api/wrapper-array/destroy.md) + * [is](api/wrapper-array/is.md) + * [isEmpty](api/wrapper-array/isEmpty.md) + * [isVueInstance](api/wrapper-array/isVueInstance.md) + * [setComputed](api/wrapper-array/setComputed.md) + * [setData](api/wrapper-array/setData.md) + * [setMethods](api/wrapper-array/setMethods.md) + * [setProps](api/wrapper-array/setProps.md) + * [trigger](api/wrapper-array/trigger.md) + * [Компоненты](api/components/README.md) + * [TransitionStub](api/components/TransitionStub.md) + * [TransitionGroupStub](api/components/TransitionGroupStub.md) + * [Селекторы](api/selectors.md) + * [createLocalVue](api/createLocalVue.md) + * [Конфигурация](api/config.md) diff --git a/docs/ru/api/README.md b/docs/ru/api/README.md new file mode 100644 index 000000000..85e1c030d --- /dev/null +++ b/docs/ru/api/README.md @@ -0,0 +1,56 @@ +# API + +* [mount](./mount.md) +* [shallow](./shallow.md) +* [Опции монтирования](./options.md) + - [context](./options.md#context) + - [slots](./options.md#slots) + - [stubs](./options.md#stubs) + - [mocks](./options.md#mocks) + - [localVue](./options.md#localvue) + - [attachToDocument](./options.md#attachtodocument) + - [attrs](./options.md#attrs) + - [listeners](./options.md#listeners) + - [provide](./options.md#provide) + - [другие опции](./options.md#other-options) +* [Wrapper](./wrapper/README.md) + * [attributes](./wrapper/attributes.md) + * [classes](./wrapper/classes.md) + * [contains](./wrapper/contains.md) + * [emitted](./wrapper/emitted.md) + * [emittedByOrder](./wrapper/emittedByOrder.md) + * [exists](./wrapper/exists.md) + * [destroy](./wrapper/destroy.md) + * [find](./wrapper/find.md) + * [findAll](./wrapper/findAll.md) + * [html](./wrapper/html.md) + * [is](./wrapper/is.md) + * [isEmpty](./wrapper/isEmpty.md) + * [isVueInstance](./wrapper/isVueInstance.md) + * [name](./wrapper/name.md) + * [props](./wrapper/props.md) + * [setComputed](./wrapper/setComputed.md) + * [setData](./wrapper/setData.md) + * [setMethods](./wrapper/setMethods.md) + * [setProps](./wrapper/setProps.md) + * [text](./wrapper/text.md) + * [trigger](./wrapper/trigger.md) +* [WrapperArray](./wrapper-array/README.md) + * [at](./wrapper-array/at.md) + * [contains](./wrapper-array/contains.md) + * [exists](./wrapper/exists.md) + * [destroy](./wrapper-array/destroy.md) + * [is](./wrapper-array/is.md) + * [isEmpty](./wrapper-array/isEmpty.md) + * [isVueInstance](./wrapper-array/isVueInstance.md) + * [setComputed](./wrapper-array/setComputed.md) + * [setData](./wrapper-array/setData.md) + * [setMethods](./wrapper-array/setMethods.md) + * [setProps](./wrapper-array/setProps.md) + * [trigger](./wrapper-array/trigger.md) +* [Компоненты](./components/README.md) + * [TransitionStub](./components/TransitionStub.md) + * [TransitionGroupStub](./components/TransitionGroupStub.md) +* [Селекторы](./selectors.md) +* [createLocalVue](./createLocalVue.md) +* [Конфигурация](./config.md) diff --git a/docs/ru/api/components/README.md b/docs/ru/api/components/README.md new file mode 100644 index 000000000..517cd1895 --- /dev/null +++ b/docs/ru/api/components/README.md @@ -0,0 +1,5 @@ +# Компоненты + +vue-test-utils включает утилиты, которые вы можете использовать для создания заглушек компонентов. + +[TransitionStub](./TransitionStub.md) и [TransitionGroupStub](./TransitionGroupStub.md) используются для создания заглушек компонентов `transition` и `transition-group` по умолчанию. Вы можете изменить эти заглушки отредактировав конфигурацию. \ No newline at end of file diff --git a/docs/ru/api/components/TransitionGroupStub.md b/docs/ru/api/components/TransitionGroupStub.md new file mode 100644 index 000000000..b87fbaf29 --- /dev/null +++ b/docs/ru/api/components/TransitionGroupStub.md @@ -0,0 +1,31 @@ +# TransitionGroupStub + +Компонент для создания заглушки компонента `transition-group`. Вместо асинхронного выполнения переходов он возвращает дочерние компоненты синхронно. + +Это настроено на заглушку всех компонентов `transition-group` по умолчанию в конфигурации vue-test-utils. Чтобы использовать стандартный компонент `transition-group` установите `config.stubs['transition-group']` в значение false: + +```js +import { config } from '@vue/test-utils' + +config.stubs['transition-group'] = false +``` + +Чтобы переустановить обратно на заглушки компонентов `transition-group`: + +```js +import { config, TransitionGroupStub } from '@vue/test-utils' + +config.stubs['transition-group'] = TransitionGroupStub +``` + +Для установки заглушек в настройках монтирования: + +```js +import { mount, TransitionGroupStub } from '@vue/test-utils' + +mount(Component, { + stubs: { + 'transition-group': TransitionGroupStub + } +}) +``` \ No newline at end of file diff --git a/docs/ru/api/components/TransitionStub.md b/docs/ru/api/components/TransitionStub.md new file mode 100644 index 000000000..acd449851 --- /dev/null +++ b/docs/ru/api/components/TransitionStub.md @@ -0,0 +1,30 @@ +# TransitionStub + +Компонент для создания заглушки компонента `transition`. Вместо асинхронного выполнения переходов он возвращает дочерний компонент синхронно. + +Это настроено на заглушку всех компонентов `transition` по умолчанию в конфигурации vue-test-utils. Чтобы использовать стандартный компонент `transition` установите `config.stubs.transition` в значение false: + +```js +import { config } from '@vue/test-utils' + +config.stubs.transition = false +``` + +Чтобы переустановить обратно на заглушки компонентов `transition`: +```js +import { config, TransitionStub } from '@vue/test-utils' + +config.stubs.transition = TransitionStub +``` + +Для установки заглушек в настройках монтирования: + +```js +import { mount, TransitionStub } from '@vue/test-utils' + +mount(Component, { + stubs: { + transition: TransitionStub + } +}) +``` \ No newline at end of file diff --git a/docs/ru/api/config.md b/docs/ru/api/config.md new file mode 100644 index 000000000..bcaec9132 --- /dev/null +++ b/docs/ru/api/config.md @@ -0,0 +1,26 @@ +# Конфигурация + +vue-test-utils включает в себя объект конфигурации для определения опций, используемых vue-test-utils. + +## Конфигурация настроек `vue-test-utils` + +### `stubs` + +- Тип: `Object` +- По умолчанию: `{ + transition: TransitionStub, + 'transition-group': TransitionGroupStub +}` + +Заглушки указанные в `config.stubs` используются по умолчанию. +Заглушки, используемые в компонентах. Они перезаписываются значениями `stubs` переданными в настройках монтирования. + +При передаче `stubs` в качестве массива в настройках монтирования, `config.stubs` будет преобразована в массив, и будут создаваться компоненты заглушки с базовым компонентом, который возвращает div. + +Пример: + +```js +import VueTestUtils from '@vue/test-utils' + +VueTestUtils.config.stubs['my-component'] = '
' +``` \ No newline at end of file diff --git a/docs/ru/api/createLocalVue.md b/docs/ru/api/createLocalVue.md new file mode 100644 index 000000000..00e9117e0 --- /dev/null +++ b/docs/ru/api/createLocalVue.md @@ -0,0 +1,27 @@ +# `createLocalVue()` + +- **Возвращает:** + - `{Component}` + +- **Использование:** + +`createLocalVue` возвращает класс Vue, чтобы вы могли добавлять компоненты, примеси и устанавливать плагины без загрузнения глобального класса Vue. + +Используйте вместе с `options.localVue`: + +```js +import { createLocalVue, shallow } from '@vue/test-utils' +import Foo from './Foo.vue' + +const localVue = createLocalVue() +const wrapper = shallow(Foo, { + localVue, + mocks: { foo: true } +}) +expect(wrapper.vm.foo).toBe(true) + +const freshWrapper = shallow(Foo) +expect(freshWrapper.vm.foo).toBe(false) +``` + +- **См. также:** [Общие советы](../guides/common-tips.md#applying-global-plugins-and-mixins) diff --git a/docs/ru/api/mount.md b/docs/ru/api/mount.md new file mode 100644 index 000000000..3717e9324 --- /dev/null +++ b/docs/ru/api/mount.md @@ -0,0 +1,130 @@ +# `mount(component [, options])` + +- **Принимает:** + + - `{Component} component` + - `{Object} options` + +- **Возвращает:** `{Wrapper}` + +- **Опции:** + +См. [опции монтирования](options.md) + +- **Использование:** + +Создаёт [`Wrapper`](wrapper/README.md), который содержит примонтированный и отрендеренный компонент Vue. + +**Без опций:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +describe('Foo', () => { + it('renders a div', () => { + const wrapper = mount(Foo) + expect(wrapper.contains('div')).toBe(true) + }) +}) +``` + +**С опциями Vue:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +describe('Foo', () => { + it('renders a div', () => { + const wrapper = mount(Foo, { + propsData: { + color: 'red' + } + }) + expect(wrapper.props().color).toBe('red') + }) +}) +``` + +**Прикрепление к DOM:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +describe('Foo', () => { + it('renders a div', () => { + const wrapper = mount(Foo, { + attachToDocument: true + }) + expect(wrapper.contains('div')).toBe(true) + }) +}) +``` + +**Слот по умолчанию и именованные слоты:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' +import FooBar from './FooBar.vue' + +describe('Foo', () => { + it('renders a div', () => { + const wrapper = mount(Foo, { + slots: { + default: [Bar, FooBar], + fooBar: FooBar, // будет соответствовать `` + foo: '
' + } + }) + expect(wrapper.contains('div')).toBe(true) + }) +}) +``` + +**Заглушки глобальных свойств:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +describe('Foo', () => { + it('renders a div', () => { + const $route = { path: 'http://www.example-path.com' } + const wrapper = mount(Foo, { + mocks: { + $route + } + }) + expect(wrapper.vm.$route.path).toBe($route.path) + }) +}) +``` + +**Заглушки компонентов:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' +import Faz from './Faz.vue' + +describe('Foo', () => { + it('renders a div', () => { + const wrapper = mount(Foo, { + stubs: { + Bar: '
', + BarFoo: true, + FooBar: Faz + } + }) + expect(wrapper.contains('.stubbed')).toBe(true) + expect(wrapper.contains(Bar)).toBe(true) + }) +}) +``` + +- **См. также:** [Wrapper](wrapper/README.md) diff --git a/docs/ru/api/options.md b/docs/ru/api/options.md new file mode 100644 index 000000000..9152c191c --- /dev/null +++ b/docs/ru/api/options.md @@ -0,0 +1,197 @@ +# Опции монтирования + +Опции для `mount` и `shallow`. Объект опций может содержать как настройки монтирования `vue-test-utils`, так и сырые опции Vue. + +## Специальные опции монтирования `vue-test-utils` + +- [`context`](#context) +- [`slots`](#slots) +- [`stubs`](#stubs) +- [`mocks`](#mocks) +- [`localVue`](#localvue) +- [`attachToDocument`](#attachtodocument) +- [`attrs`](#attrs) +- [`listeners`](#listeners) +- [`provide`](#provide) + +### `context` + +- Тип: `Object` + +Передаёт контекст в функциональный компонент. Может использоваться только с функциональными компонентами. + +Пример: + +```js +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = mount(Component, { + context: { + props: { show: true }, + children: [Foo, Bar] + } +}) + +expect(wrapper.is(Component)).toBe(true) +``` + +### `slots` + +- Тип: `{ [name: string]: Array|Component|string }` + +Предоставляет объект с содержимым слотов компоненту. Ключ соответствует имени слота. Значение может быть компонентом, массивом компонентов или строковым шаблоном, или текстом. + +Пример: + +```js +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = shallow(Component, { + slots: { + default: [Foo, Bar], + fooBar: Foo, // будет соответствовать `` + foo: '
', + bar: 'bar' + } +}) +expect(wrapper.find('div')).toBe(true) +``` + +#### Передача текста + +Вы можете передать текст в `slots`. +Для этого есть одно ограничение. + +Это не поддерживается PhantomJS. +Используйте [Puppeteer](https://github.com/karma-runner/karma-chrome-launcher#headless-chromium-with-puppeteer). + +### `stubs` + +- Тип: `{ [name: string]: Component | boolean } | Array` + +Заглушки дочерних компонентов. Может быть массивом имен компонентов заменяемых заглушкой, или объектом. + +Пример: + +```js +import Foo from './Foo.vue' + +mount(Component, { + stubs: ['registered-component'] +}) + +shallow(Component, { + stubs: { + // заглушка со специальной реализацией + 'registered-component': Foo, + // создание обычной заглушки + 'another-component': true + } +}) +``` + +### `mocks` + +- Тип: `Object` + +Дополнительные свойства для экземпляра. Полезно при создании моков глобальных инъекций. + +Пример: + +```js +const $route = { path: 'http://www.example-path.com' } +const wrapper = shallow(Component, { + mocks: { + $route + } +}) +expect(wrapper.vm.$route.path).toBe($route.path) +``` + +### `localVue` + +- Тип: `Vue` + +Локальная копия Vue, созданная с помощью [`createLocalVue`](./createLocalVue.md) для использования при монтировании компонента. Установка плагинов на этой копии `Vue` предотвращает загрязнение оригинальной копии `Vue`. + +Пример: + +```js +import { createLocalVue, mount } from '@vue/test-utils' +import VueRouter from 'vue-router' +import Foo from './Foo.vue' + +const localVue = createLocalVue() +localVue.use(VueRouter) + +const routes = [ + { path: '/foo', component: Foo } +] + +const router = new VueRouter({ + routes +}) + +const wrapper = mount(Component, { + localVue, + router +}) +expect(wrapper.vm.$route).toBeInstanceOf(Object) +``` + +### `attachToDocument` + +- Тип: `boolean` +- По умолчанию: `false` + +Компонент будет прикрепляться к DOM при рендеринге, если установлено в `true`. + +### `attrs` + +- Тип: `Object` + +Устанавливает объект `$attrs` на экземпляре компонента. + +### `listeners` + +- Тип: `Object` + +Устанавливает объект `$listeners` на экземпляре компонента. + +### `provide` + +- Тип: `Object` + +Передаёт свойства в компоненты для использования в инъекциях. См. [provide/inject](https://ru.vuejs.org/v2/api/#provide-inject). + +## Другие опции + +Если в параметрах для `mount` и `shallow` содержатся другие опции, отличные от опций монтирования, опции компонента будут перезаписаны с помощью [extends](https://ru.vuejs.org/v2/api/#extends). + +```js +const Component = { + template: '
{{ foo() }}{{ bar() }}{{ baz() }}
', + methods: { + foo () { + return 'a' + }, + bar () { + return 'b' + } + } +} +const options = { + methods: { + bar () { + return 'B' + }, + baz () { + return 'C' + } + } +} +const wrapper = mount(Component, options) +expect(wrapper.text()).toBe('aBC') +``` \ No newline at end of file diff --git a/docs/ru/api/selectors.md b/docs/ru/api/selectors.md new file mode 100644 index 000000000..0c00a3032 --- /dev/null +++ b/docs/ru/api/selectors.md @@ -0,0 +1,60 @@ +# Селекторы + +Многие методы принимают селектор в качестве аргумента. Селектором может быть CSS селектор, компонент Vue или опция поиска объекта. + +## CSS селекторы + +Обрабатывают любой допустимый CSS селектор: + +- селекторы тегов (`div`, `foo`, `bar`) +- селекторы классов (`.foo`, `.bar`) +- селекторы атрибутов (`[foo]`, `[foo="bar"]`) +- селекторы id (`#foo`, `#bar`) +- селекторы псевдо-элементов (`div:first-of-type`) + +Вы также можете использовать комбинации: + +- выбор только непосредственных потомков (`div > #bar > .foo`) +- выбор элементов, являющихся потомками (`div #bar .foo`) +- селектор выбора соседа идущего за элементом (`div + .foo`) +- селектор выбора соседей идущих после элемента (`div ~ .foo`) + +## Компоненты Vue + +Компоненты Vue также являются допустимыми селекторами. + +```js +// Foo.vue + +export default { + name: 'FooComponent' +} +``` + +```js +import { shallow } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = shallow(Foo) +expect(wrapper.is(Foo)).toBe(true) +``` + +## Опция поиска объекта + +### Name + +Использование объекта для опции поиска, позволяет `vue-test-utils` выбирать элементы по `name` компонента на компонентах обёртках. + +```js +const buttonWrapper = wrapper.find({ name: 'my-button' }) +buttonWrapper.trigger('click') +``` + +### Ref + +Использование опции поиска объекта позволяет `vue-test-utils` выбирать элементы по `$ref` на компонентах обёрток. + +```js +const buttonWrapper = wrapper.find({ ref: 'myButton' }) +buttonWrapper.trigger('click') +``` diff --git a/docs/ru/api/shallow.md b/docs/ru/api/shallow.md new file mode 100644 index 000000000..4e9eb514f --- /dev/null +++ b/docs/ru/api/shallow.md @@ -0,0 +1,114 @@ +# `shallow(component [, options])` + +- **Принимает:** + + - `{Component} component` + - `{Object} options` + - `{boolean} attachToDocument` + - `{Object} context` + - `{Array|Component} children` + - `{Object} slots` + - `{Array|Component|String} default` + - `{Array|Component|String} named` + - `{Object} mocks` + - `{Object|Array} stubs` + - `{Vue} localVue` + +- **Возвращает:** `{Wrapper}` + +- **Опции:** + +См. [опции монтирования](./options.md) + +- **Использование:** + +Аналогично [`mount`](mount.md), создаёт [`Wrapper`](wrapper/README.md), который содержит примонтированный и отрендеренный компонент Vue, но с заглушками вместо дочерних компонентов. + +**Без опций:** + +```js +import { shallow } from '@vue/test-utils' +import Foo from './Foo.vue' + +describe('Foo', () => { + it('renders a div', () => { + const wrapper = shallow(Foo) + expect(wrapper.contains('div')).toBe(true) + }) +}) +``` + +**С опциями Vue:** + +```js +import { shallow } from '@vue/test-utils' +import Foo from './Foo.vue' + +describe('Foo', () => { + it('renders a div', () => { + const wrapper = shallow(Foo, { + propsData: { + color: 'red' + } + }) + expect(wrapper.props().color).toBe('red') + }) +}) +``` + +**Прикрепление к DOM:** + +```js +import { shallow } from '@vue/test-utils' +import Foo from './Foo.vue' + +describe('Foo', () => { + it('renders a div', () => { + const wrapper = shallow(Foo, { + attachToDocument: true + }) + expect(wrapper.contains('div')).toBe(true) + }) +}) +``` + +**Слот по умолчанию и именованные слоты:** + +```js +import { shallow } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' +import FooBar from './FooBar.vue' + +describe('Foo', () => { + it('renders a div', () => { + const wrapper = shallow(Foo, { + slots: { + default: [Bar, FooBar], + fooBar: FooBar, // будет соответствовать , + foo: '
' + } + }) + expect(wrapper.find('div')).toBe(true) + }) +}) +``` + +**Заглушки глобальных свойств:** + +```js +import { shallow } from '@vue/test-utils' +import Foo from './Foo.vue' + +describe('Foo', () => { + it('renders a div', () => { + const $route = { path: 'http://www.example-path.com' } + const wrapper = shallow(Foo, { + mocks: { + $route + } + }) + expect(wrapper.vm.$route.path).toBe($route.path) + }) +}) +``` diff --git a/docs/ru/api/wrapper-array/README.md b/docs/ru/api/wrapper-array/README.md new file mode 100644 index 000000000..fa6a167c6 --- /dev/null +++ b/docs/ru/api/wrapper-array/README.md @@ -0,0 +1,12 @@ +# WrapperArray + +`WrapperArray` — это объект, содержащий массив [`Wrappers`](../wrapper/README.md), и методы для тестирования `Wrappers`. + +- **Свойства:** + +`wrappers` `array`: массив `Wrappers` содержащихся в `WrapperArray` +`length` `number`: количество `Wrappers` содержащихся в `WrapperArray` + + - **Методы:** + +Подробный список методов можно изучить в разделе документации о `WrapperArray`. diff --git a/docs/ru/api/wrapper-array/at.md b/docs/ru/api/wrapper-array/at.md new file mode 100644 index 000000000..ceb96c6fb --- /dev/null +++ b/docs/ru/api/wrapper-array/at.md @@ -0,0 +1,20 @@ +# at(index) + +Возвращает `Wrapper` по указанному индексу `index`. Используется нумерация с нуля (т.е. первый элемент имеет индекс 0). + +- **Принимает:** + - `{number} index` + +- **Возвращает:** `{Wrapper}` + +- **Пример:** + +```js +import { shallow } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = shallow(Foo) +const divArray = wrapper.findAll('div') +const secondDiv = divArray.at(1) +expect(secondDiv.is('p')).toBe(true) +``` diff --git a/docs/ru/api/wrapper-array/contains.md b/docs/ru/api/wrapper-array/contains.md new file mode 100644 index 000000000..eea3a3720 --- /dev/null +++ b/docs/ru/api/wrapper-array/contains.md @@ -0,0 +1,23 @@ +# contains(selector) + +Проверка, что каждый `Wrapper` в `WrapperArray` содержит указанный селектор. + +Используйте любой валидный [селектор](../selectors.md). + +- **Принимает:** + - `{string|Component} selector` + +- **Возвращает:** `{boolean}` + +- **Пример:** + +```js +import { shallow } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = shallow(Foo) +const divArray = wrapper.findAll('div') +expect(divArray.contains('p')).toBe(true) +expect(divArray.contains(Bar)).toBe(true) +``` diff --git a/docs/ru/api/wrapper-array/destroy.md b/docs/ru/api/wrapper-array/destroy.md new file mode 100644 index 000000000..aa544f3ca --- /dev/null +++ b/docs/ru/api/wrapper-array/destroy.md @@ -0,0 +1,16 @@ +# destroy() + +Уничтожает каждый `Wrapper` Vue в `WrapperArray`. + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +const divArray = wrapper.findAll('div') +expect(divArray.contains('p')).toBe(true) +divArray.destroy() +expect(divArray.contains('p')).toBe(false) +``` \ No newline at end of file diff --git a/docs/ru/api/wrapper-array/is.md b/docs/ru/api/wrapper-array/is.md new file mode 100644 index 000000000..250f11536 --- /dev/null +++ b/docs/ru/api/wrapper-array/is.md @@ -0,0 +1,19 @@ +# is(selector) + +Проверка, что каждый `Wrapper` в `WrapperArray` DOM узле или `vm` соответствует [селектору](../selectors.md). + +- **Принимает:** + - `{string|Component} selector` + +- **Возвращает:** `{boolean}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +const divArray = wrapper.find('div') +expect(divArray.is('div')).toBe(true) +``` diff --git a/docs/ru/api/wrapper-array/isEmpty.md b/docs/ru/api/wrapper-array/isEmpty.md new file mode 100644 index 000000000..d9f375a6e --- /dev/null +++ b/docs/ru/api/wrapper-array/isEmpty.md @@ -0,0 +1,16 @@ +# isEmpty() + +Проверка, что каждый `Wrapper` в `WrapperArray` не содержит дочерних узлов. + +- **Возвращает:** `{boolean}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +const divArray = wrapper.findAll('div') +expect(divArray.isEmpty()).toBe(true) +``` diff --git a/docs/ru/api/wrapper-array/isVueInstance.md b/docs/ru/api/wrapper-array/isVueInstance.md new file mode 100644 index 000000000..0117a2bf0 --- /dev/null +++ b/docs/ru/api/wrapper-array/isVueInstance.md @@ -0,0 +1,17 @@ +# isVueInstance() + +Проверка, что каждый `Wrapper` в `WrapperArray` является экземпляром Vue. + +- **Возвращает:** `{boolean}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = mount(Foo) +const barArray = wrapper.findAll(Bar) +expect(barArray.isVueInstance()).toBe(true) +``` diff --git a/docs/ru/api/wrapper-array/setComputed.md b/docs/ru/api/wrapper-array/setComputed.md new file mode 100644 index 000000000..c84b3438d --- /dev/null +++ b/docs/ru/api/wrapper-array/setComputed.md @@ -0,0 +1,25 @@ +# setComputed(computedObjects) + +Устанавливает для `Wrapper` `vm` вычисляемое свойство и принудительно обновляет каждый `Wrapper` в `WrapperArray`. + +**Каждый `Wrapper` должен содержать экземпляр Vue.** +**Каждый экземпляр Vue должен уже иметь вычисляемое свойство, переданные в `setComputed`.** + +- **Аргументы:** + - `{Object} вычисляемые свойства` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = mount(Foo) +const barArray = wrapper.findAll(Bar) + +barArray.setComputed({ + computed1: 'new-computed1', + computed2: 'new-computed2' +}) +``` \ No newline at end of file diff --git a/docs/ru/api/wrapper-array/setData.md b/docs/ru/api/wrapper-array/setData.md new file mode 100644 index 000000000..557e22960 --- /dev/null +++ b/docs/ru/api/wrapper-array/setData.md @@ -0,0 +1,21 @@ +# setData(data) + +Устанавливает данные `Wrapper` `vm` и выполняет принудительное обновление каждого `Wrapper` в `WrapperArray`. + +**Обратите внимание, что каждый `Wrapper` должен содержать экземпляр Vue.** + +- **Принимает:** + - `{Object} data` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = mount(Foo) +const barArray = wrapper.findAll(Bar) +barArray.setData({ foo: 'bar' }) +expect(barArray.at(0).vm.foo).toBe('bar') +``` diff --git a/docs/ru/api/wrapper-array/setMethods.md b/docs/ru/api/wrapper-array/setMethods.md new file mode 100644 index 000000000..c5a128055 --- /dev/null +++ b/docs/ru/api/wrapper-array/setMethods.md @@ -0,0 +1,26 @@ + +# setMethods(methods) + +Устанавливает методы `Wrapper` `vm` и выполняет принудительное обновление каждого `Wrapper` в `WrapperArray`. + +**Обратите внимание, что каждый `Wrapper` должен содержать экземпляр Vue.** + +- **Принимает:** + - `{Object} methods` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import sinon from 'sinon' +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = mount(Foo) +const barArray = wrapper.findAll(Bar) +const clickMethodStub = sinon.stub() + +barArray.setMethods({ clickMethod: clickMethodStub }) +barArray.at(0).trigger('click') +expect(clickMethodStub.called).toBe(true) +``` diff --git a/docs/ru/api/wrapper-array/setProps.md b/docs/ru/api/wrapper-array/setProps.md new file mode 100644 index 000000000..e5b3751c4 --- /dev/null +++ b/docs/ru/api/wrapper-array/setProps.md @@ -0,0 +1,21 @@ +# setProps(props) + +Устанавливает входные параметры `Wrapper` `vm` и выполняет принудительное обновление каждого `Wrapper` в `WrapperArray`. + +**Обратите внимание, что каждый `Wrapper` должен содержать экземпляр Vue.** + +- **Принимает:** + - `{Object} props` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = mount(Foo) +const barArray = wrapper.findAll(Bar) +barArray.setProps({ foo: 'bar' }) +expect(barArray.at(0).vm.foo).toBe('bar') +``` diff --git a/docs/ru/api/wrapper-array/trigger.md b/docs/ru/api/wrapper-array/trigger.md new file mode 100644 index 000000000..593c8d37a --- /dev/null +++ b/docs/ru/api/wrapper-array/trigger.md @@ -0,0 +1,25 @@ +# trigger(eventName) + +Генерирует событие на каждом `Wrapper` в `WrapperArray` DOM узле. + +**Обратите внимание, что каждый `Wrapper` должен содержать экземпляр Vue.** + +- **Принимает:** + - `{string} eventName` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import sinon from 'sinon' +import Foo from './Foo.vue' + +const clickHandler = sinon.stub() +const wrapper = mount(Foo, { + propsData: { clickHandler } +}) + +const divArray = wrapper.findAll('div') +divArray.trigger('click') +expect(clickHandler.called).toBe(true) +``` diff --git a/docs/ru/api/wrapper/README.md b/docs/ru/api/wrapper/README.md new file mode 100644 index 000000000..4a6b6b44d --- /dev/null +++ b/docs/ru/api/wrapper/README.md @@ -0,0 +1,16 @@ +# `Wrapper` + +`vue-test-utils` — это API основанное на использовании обёрток (wrapper). + +`Wrapper` — это объект, который содержит примонтированный компонент или VNode и методы для тестирования компонента или VNnode. + +- **Свойства:** + +`vm` `Component`: это экземпляр `Vue`. Вы можете получить доступ ко всем [методам и свойствам экземпляра](https://ru.vuejs.org/v2/api/index.html#Опции-—-данные) через `wrapper.vm`. Это существует только в обёртках для компонентов Vue +`element` `HTMLElement`: корневой DOM-узел обёртки +`options` `Object`: Объект содержащий опции `vue-test-utils`, передаваемые в `mount` или `shallow` +`options.attachedToDom` `Boolean`: `true` если был передан `attachToDom` в `mount` или `shallow` + +- **Методы:** + +Подробный список методов можно изучить в разделе документации про wrapper. diff --git a/docs/ru/api/wrapper/attributes.md b/docs/ru/api/wrapper/attributes.md new file mode 100644 index 000000000..04a5990a8 --- /dev/null +++ b/docs/ru/api/wrapper/attributes.md @@ -0,0 +1,15 @@ +# attributes() + +Возвращает объект атрибутов DOM-узла `Wrapper`. + +- **Возвращает:** `{[attribute: string]: any}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +expect(wrapper.attributes().id).toBe('foo') +``` \ No newline at end of file diff --git a/docs/ru/api/wrapper/classes.md b/docs/ru/api/wrapper/classes.md new file mode 100644 index 000000000..4da728cbf --- /dev/null +++ b/docs/ru/api/wrapper/classes.md @@ -0,0 +1,17 @@ +# classes() + +Возвращает классы DOM-узла `Wrapper`. + +Возвращает массив имён классов. + +- **Возвращает:** `Array<{string}>` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +expect(wrapper.classes()).toContain('bar') +``` \ No newline at end of file diff --git a/docs/ru/api/wrapper/contains.md b/docs/ru/api/wrapper/contains.md new file mode 100644 index 000000000..064ae3bcc --- /dev/null +++ b/docs/ru/api/wrapper/contains.md @@ -0,0 +1,22 @@ +# `contains(selector)` + +Проверка, что `Wrapper` содержит элемент или компонент, соответствующий [селектору](../selectors.md). + +- **Принимает:** + - `{string|Component} selector` + +- **Возвращает:** `{boolean}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = mount(Foo) +expect(wrapper.contains('p')).toBe(true) +expect(wrapper.contains(Bar)).toBe(true) +``` + +- **См. также:** [Селекторы](../selectors.md) diff --git a/docs/ru/api/wrapper/destroy.md b/docs/ru/api/wrapper/destroy.md new file mode 100644 index 000000000..9eb06baa3 --- /dev/null +++ b/docs/ru/api/wrapper/destroy.md @@ -0,0 +1,19 @@ +# destroy() + +Уничтожает экземпляр компонента Vue. + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import sinon from 'sinon' + +const spy = sinon.stub() +mount({ + render: null, + destroyed () { + spy() + } +}).destroy() +expect(spy.calledOnce).toBe(true) +``` \ No newline at end of file diff --git a/docs/ru/api/wrapper/emitted.md b/docs/ru/api/wrapper/emitted.md new file mode 100644 index 000000000..97ab6f327 --- /dev/null +++ b/docs/ru/api/wrapper/emitted.md @@ -0,0 +1,57 @@ +# emitted() + +Возвращает объект, содержащий вызванные пользовательские события в `Wrapper` `vm`. + +- **Возвращает:** `{ [name: string]: Array> }` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' + +const wrapper = mount(Component) + +wrapper.vm.$emit('foo') +wrapper.vm.$emit('foo', 123) + +/* +wrapper.emitted() возвращает следующий объект: +{ + foo: [[], [123]] +} +*/ + +// проверка, что событие было вызвано +expect(wrapper.emitted().foo).toBeTruthy() + +// проверка, что событие вызывалось определённое число раз +expect(wrapper.emitted().foo.length).toBe(2) + +// проверка, что с событием были переданы определённые данные +expect(wrapper.emitted().foo[1]).toEqual([123]) +``` + +Вы также можете написать это так: + +```js +// проверка, что событие было вызвано +expect(wrapper.emitted('foo')).toBeTruthy() + +// проверка, что событие вызывалось определённое число раз +expect(wrapper.emitted('foo').length).toBe(2) + +// проверка, что с событием были переданы определённые данные +expect(wrapper.emitted('foo')[1]).toEqual([123]) +``` + +Метод `.emitted()`, когда он вызывается, каждый раз возвращает тот же объект, а не новый, поэтому объект будет обновляться при генерации новых событий: + +```js +const emitted = wrapper.emitted() + +expect(emitted.foo.length).toBe(1) + +// делаем что-то, что заставляет `wrapper` сгенерировать событие "foo" + +expect(emitted.foo.length).toBe(2) +``` \ No newline at end of file diff --git a/docs/ru/api/wrapper/emittedByOrder.md b/docs/ru/api/wrapper/emittedByOrder.md new file mode 100644 index 000000000..fc0820ad3 --- /dev/null +++ b/docs/ru/api/wrapper/emittedByOrder.md @@ -0,0 +1,27 @@ +# emittedByOrder() + +Возвращает массив, содержащий вызванные пользовательские события в `Wrapper` `vm`. + +- **Возвращает:** `Array<{ name: string, args: Array }>` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' + +const wrapper = mount(Component) + +wrapper.vm.$emit('foo') +wrapper.vm.$emit('bar', 123) + +/* +wrapper.emittedByOrder() возвращает следующий массив: +[ + { name: 'foo', args: [] }, + { name: 'bar', args: [123] } +] +*/ + +// проверка, что события были вызваны в определённом порядке +expect(wrapper.emittedByOrder().map(e => e.name)).toEqual(['foo', 'bar']) +``` diff --git a/docs/ru/api/wrapper/exists.md b/docs/ru/api/wrapper/exists.md new file mode 100644 index 000000000..ca56c4e53 --- /dev/null +++ b/docs/ru/api/wrapper/exists.md @@ -0,0 +1,20 @@ +# exists() + +Проверка, что `Wrapper` или `WrapperArray` существует. + +Возвращает `false` если вызывается на пустом `Wrapper` или `WrapperArray`. + +- **Возвращает:** `{boolean}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +expect(wrapper.exists()).toBe(true) +expect(wrapper.find('does-not-exist').exists()).toBe(false) +expect(wrapper.findAll('div').exists()).toBe(true) +expect(wrapper.findAll('does-not-exist').exists()).toBe(false) +``` diff --git a/docs/ru/api/wrapper/find.md b/docs/ru/api/wrapper/find.md new file mode 100644 index 000000000..8f5df5cdc --- /dev/null +++ b/docs/ru/api/wrapper/find.md @@ -0,0 +1,26 @@ +# find(selector) + +Возвращает [`Wrapper`](README.md) первого DOM узла или компонента Vue, соответствующий селектору. + +Используйте любой валидный [селектор](../selectors.md). + +- **Принимает:** + - `{string|Component} selector` + +- **Возвращает:** `{Wrapper}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = mount(Foo) +const div = wrapper.find('div') +expect(div.is('div')).toBe(true) +const bar = wrapper.find(Bar) +expect(bar.is(Bar)).toBe(true) +``` + +- **См. также:** [Wrapper](README.md) diff --git a/docs/ru/api/wrapper/findAll.md b/docs/ru/api/wrapper/findAll.md new file mode 100644 index 000000000..a6b69715a --- /dev/null +++ b/docs/ru/api/wrapper/findAll.md @@ -0,0 +1,26 @@ +# findAll(selector) + +Возвращает [`WrapperArray`](../wrapper-array/README.md), состоящий из [Wrappers](README.md). + +Используйте любой валидный [селектор](../selectors.md). + +- **Принимает:** + - `{string|Component} selector` + +- **Возвращает:** `{WrapperArray}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' +import Bar from './Bar.vue' + +const wrapper = mount(Foo) +const div = wrapper.findAll('div').at(0) +expect(div.is('div')).toBe(true) +const bar = wrapper.findAll(Bar).at(0) +expect(bar.is(Bar)).toBe(true) +``` + +- **См. также:** [Wrapper](README.md) diff --git a/docs/ru/api/wrapper/html.md b/docs/ru/api/wrapper/html.md new file mode 100644 index 000000000..bfe5031ee --- /dev/null +++ b/docs/ru/api/wrapper/html.md @@ -0,0 +1,15 @@ +# html() + +Возвращает HTML `Wrapper` DOM узла в виде строки. + +- **Возвращает:** `{string}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +expect(wrapper.html()).toBe('

Foo

') +``` diff --git a/docs/ru/api/wrapper/is.md b/docs/ru/api/wrapper/is.md new file mode 100644 index 000000000..06f6141e3 --- /dev/null +++ b/docs/ru/api/wrapper/is.md @@ -0,0 +1,18 @@ +# is(selector) + +Проверяет, что DOM-элемент `Wrapper` или `vm` соответствуют [селектору](../selectors.md). + +- **Принимает:** + - `{string|Component} selector` + +- **Возвращает:** `{boolean}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +expect(wrapper.is('div')).toBe(true) +``` diff --git a/docs/ru/api/wrapper/isEmpty.md b/docs/ru/api/wrapper/isEmpty.md new file mode 100644 index 000000000..908de15c9 --- /dev/null +++ b/docs/ru/api/wrapper/isEmpty.md @@ -0,0 +1,15 @@ +# isEmpty() + +Проверяет, что `Wrapper` не содержит дочерних узлов. + +- **Возвращает:** `{boolean}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +expect(wrapper.isEmpty()).toBe(true) +``` diff --git a/docs/ru/api/wrapper/isVueInstance.md b/docs/ru/api/wrapper/isVueInstance.md new file mode 100644 index 000000000..fe83892e0 --- /dev/null +++ b/docs/ru/api/wrapper/isVueInstance.md @@ -0,0 +1,15 @@ +# isVueInstance() + +Проверка, что `Wrapper` является экземпляром Vue. + +- **Возвращает:** `{boolean}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +expect(wrapper.isVueInstance()).toBe(true) +``` diff --git a/docs/ru/api/wrapper/name.md b/docs/ru/api/wrapper/name.md new file mode 100644 index 000000000..4a46d21e8 --- /dev/null +++ b/docs/ru/api/wrapper/name.md @@ -0,0 +1,17 @@ +# name() + +Возвращает имя компонента, если `Wrapper` содержит экземпляр Vue, или имя тега DOM-узла `Wrapper` если `Wrapper` не содержит экземпляра Vue. + +- **Возвращает:** `{string}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +expect(wrapper.name()).toBe('Foo') +const p = wrapper.find('p') +expect(p.name()).toBe('p') +``` diff --git a/docs/ru/api/wrapper/props.md b/docs/ru/api/wrapper/props.md new file mode 100644 index 000000000..827606ee2 --- /dev/null +++ b/docs/ru/api/wrapper/props.md @@ -0,0 +1,21 @@ +# props() + +Возвращает объект с входными параметрами `vm` для `Wrapper`. + +**Обратите внимание что Wrapper должен содержать экземпляр Vue.** + +- **Возвращает:** `{[prop: string]: any}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo, { + propsData: { + bar: 'baz' + } +}) +expect(wrapper.props().bar).toBe('baz') +``` \ No newline at end of file diff --git a/docs/ru/api/wrapper/setData.md b/docs/ru/api/wrapper/setData.md new file mode 100644 index 000000000..f5e9f76bc --- /dev/null +++ b/docs/ru/api/wrapper/setData.md @@ -0,0 +1,19 @@ +# setData(data) + +Устанавливает данные `Wrapper` `vm` и выполняет принудительное обновление. + +**Обратите внимание, что `Wrapper` должен содержать экземпляр Vue.** + +- **Принимает:** + - `{Object} data` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +wrapper.setData({ foo: 'bar' }) +expect(wrapper.vm.foo).toBe('bar') +``` diff --git a/docs/ru/api/wrapper/setMethods.md b/docs/ru/api/wrapper/setMethods.md new file mode 100644 index 000000000..8bc728dfe --- /dev/null +++ b/docs/ru/api/wrapper/setMethods.md @@ -0,0 +1,23 @@ +# setMethods(methods) + +Устанавливает методы `Wrapper` `vm` и выполняет принудительное обновление. + +**Обратите внимание, что `Wrapper` должен содержать экземпляр Vue.** + +- **Принимает:** + - `{Object} methods` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import sinon from 'sinon' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +const clickMethodStub = sinon.stub() + +wrapper.setMethods({ clickMethod: clickMethodStub }) +wrapper.find('button').trigger('click') +expect(clickMethodStub.called).toBe(true) +``` diff --git a/docs/ru/api/wrapper/setProps.md b/docs/ru/api/wrapper/setProps.md new file mode 100644 index 000000000..31d2db8fa --- /dev/null +++ b/docs/ru/api/wrapper/setProps.md @@ -0,0 +1,46 @@ +# setProps(props) + +- **Принимает:** + - `{Object} props` + +- **Использование:** + +Устанавливает входные параметры `Wrapper` `vm` и выполняет принудительное обновление. + +**Обратите внимание, что `Wrapper` должен содержать экземпляр Vue.** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +wrapper.setProps({ foo: 'bar' }) +expect(wrapper.vm.foo).toBe('bar') +``` + +Вы также можете передать объект `propsData`, который инициализирует экземпляр Vue с переданными значениями. + +``` js +// Foo.vue +export default { + props: { + foo: { + type: String, + required: true + } + } +} +``` + +``` js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo, { + propsData: { + foo: 'bar' + } +}) + +expect(wrapper.vm.foo).toBe('bar') +``` \ No newline at end of file diff --git a/docs/ru/api/wrapper/text.md b/docs/ru/api/wrapper/text.md new file mode 100644 index 000000000..f62ba500f --- /dev/null +++ b/docs/ru/api/wrapper/text.md @@ -0,0 +1,15 @@ +# text() + +Возвращает текстовое содержимое `Wrapper`. + +- **Возвращает:** `{string}` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = mount(Foo) +expect(wrapper.text()).toBe('bar') +``` diff --git a/docs/ru/api/wrapper/trigger.md b/docs/ru/api/wrapper/trigger.md new file mode 100644 index 000000000..f2199dca3 --- /dev/null +++ b/docs/ru/api/wrapper/trigger.md @@ -0,0 +1,44 @@ +# trigger(eventName) + +Вызывает событие на `Wrapper` DOM узле. + +В `trigger` также можно передать опциональный объект `options`. Свойства объекта `options` будут добавлены к Event. + +- **Принимает:** + - `{string} eventName` + - `{Object} options` + +- **Пример:** + +```js +import { mount } from '@vue/test-utils' +import sinon from 'sinon' +import Foo from './Foo' + +const clickHandler = sinon.stub() +const wrapper = mount(Foo, { + propsData: { clickHandler } +}) + +wrapper.trigger('click') + +wrapper.trigger('click', { + button: 0 +}) + +expect(clickHandler.called).toBe(true) +``` + +- **Установка target для event:** + +Под капотом, `trigger` создаёт объект `Event` и вызывает событие на элементе Wrapper. + +Невозможно изменить значение `target` объекта `Event`, поэтому вы не можете установить `target` в объекте опций. + +Чтобы добавить атрибут к `target`, вам нужно установить значение элемента Wrapper перед вызовом `trigger`. Вы можете сделать это с помощью свойства `element`. + +```js +const input = wrapper.find('input') +input.element.value = 100 +input.trigger('click') +``` \ No newline at end of file diff --git a/docs/ru/guides/README.md b/docs/ru/guides/README.md new file mode 100644 index 000000000..ac385ad92 --- /dev/null +++ b/docs/ru/guides/README.md @@ -0,0 +1,10 @@ +# Руководства + +* [Введение](./getting-started.md) +* [Общие советы](./common-tips.md) +* [Мышь, клавиши и другие события DOM](./dom-events.md) +* [Чем запускать тесты](./choosing-a-test-runner.md) +* [Тестирование однофайловых компонентов с Jest](./testing-SFCs-with-jest.md) +* [Тестирование однофайловых компонентов с Mocha + webpack](./testing-SFCs-with-mocha-webpack.md) +* [Использование с Vue Router](./using-with-vue-router.md) +* [Использование с Vuex](./using-with-vuex.md) diff --git a/docs/ru/guides/choosing-a-test-runner.md b/docs/ru/guides/choosing-a-test-runner.md new file mode 100644 index 000000000..0f59de271 --- /dev/null +++ b/docs/ru/guides/choosing-a-test-runner.md @@ -0,0 +1,46 @@ +# Чем запускать тесты + +Test runner — это программа, которая запускает тесты. + +Есть много популярных программ запуска тестов для JavaScript, и `vue-test-utils` работает с любой из них. Нет зависимости от используемого test runner. + +Есть несколько вещей, которые следует учитывать при выборе программы запуска тестов: набор функций, производительность и поддержка предварительной компиляции однофайловых компонентов. После тщательного сравнения существующих библиотек мы рекомендуем два варианта конфигурации: + +- [Jest](https://facebook.github.io/jest/docs/en/getting-started.html#content) наиболее функциональный способ запуска тестов. Он меньше всех требует конфигурирования, устанавливает JSDOM по умолчанию, предоставляет встроенные проверки (assertions) и имеет отличный интерфейс для работы через командную строку. Тем не менее, вам понадобится пре-процессор, чтобы иметь возможность импортировать однофайловые компоненты в свои тесты. Мы создали пре-процессор `vue-jest`, который может обрабатывать наиболее распространённые функции однофайловых компонентов, но в настоящее время он не имеет 100% паритетности функций с `vue-loader`. + +- [mocha-webpack](https://github.com/zinserjan/mocha-webpack) — это обёртка вокруг webpack + Mocha, но с более оптимизированным интерфейсом и режимом отслеживания. Преимущества этой конфигурации в том, что мы можем получить полную поддержку однофайловых компонентов с помощью webpack + `vue-loader`, но для этого требуется больше настройки. + +## Браузерное окружение + +`vue-test-utils` полагается на браузерное окружение. Технически вы можете запустить его в реальном браузере, но это не рекомендуется из-за сложности запуска реальных браузеров на разных платформах. Вместо этого мы рекомендуем запускать тесты в Node с виртуальным браузерным окружением, реализуемым с помощью [JSDOM](https://github.com/tmpvar/jsdom). + +Jest настраивает JSDOM автоматически. Для других программ запуска тестов вы можете вручную настроить JSDOM для тестов с помощью [jsdom-global](https://github.com/rstacruz/jsdom-global) в записи для ваших тестов: + +``` bash +npm install --save-dev jsdom jsdom-global +``` +--- +``` js +// в настройке теста / entry +require('jsdom-global')() +``` + +## Тестирование однофайловых компонентов + +Однофайловые компоненты Vue требуют предварительной компиляции, прежде чем могут быть запущены в Node или в браузере. Существует два рекомендуемых способа выполнения компиляции: с пре-процессором Jest, или непосредственно с помощью webpack. + +Пре-процессор `vue-jest` поддерживает базовую функциональность однофайловых компонентов, но в настоящее время не обрабатывает блоки стилей или пользовательские блоки, которые поддерживаются только в `vue-loader`. Если вы полагаетесь на эти функции или другие конфигурации, специфичные для webpack, вам нужно будет использовать связку webpack + `vue-loader`. + +Изучите следующие руководства по вариантам настройки: + +- [Тестирование однофайловых компонентов с Jest](./testing-SFCs-with-jest.md) +- [Тестирование однофайловых компонентов с Mocha + webpack](./testing-SFCs-with-mocha-webpack.md) + +## Дополнительные ресурсы + +- [Сравнение производительностей программ для запуска тестов](https://github.com/eddyerburgh/vue-unit-test-perf-comparison) +- [Пример проекта с Jest](https://github.com/vuejs/vue-test-utils-jest-example) +- [Пример проекта с Mocha](https://github.com/vuejs/vue-test-utils-mocha-webpack-example) +- [Пример проекта с tape](https://github.com/eddyerburgh/vue-test-utils-tape-example) +- [Пример проекта с AVA](https://github.com/eddyerburgh/vue-test-utils-ava-example) +- [tyu — Восхитительное веб-тестирование от egoist](https://github.com/egoist/tyu) \ No newline at end of file diff --git a/docs/ru/guides/common-tips.md b/docs/ru/guides/common-tips.md new file mode 100644 index 000000000..173ffd9af --- /dev/null +++ b/docs/ru/guides/common-tips.md @@ -0,0 +1,135 @@ +# Общие советы + +## Понимание что тестировать + +Для компонентов пользовательского интерфейса мы не рекомендуем стремиться к покрытию каждой строки кода, поскольку это приводит к слишком большому фокусу на деталях внутренней реализации компонентов и может привести к созданию хрупких тестов. + +Вместо этого, мы рекомендуем писать тесты, которые проверяют ваш публичный интерфейс взаимодействия с компонентом и относиться к его внутренностям как к чёрному ящику. Один тестовый пример должен проверять, что некоторые входные данные (взаимодействие пользователя или изменение входных параметров), предоставляемые компоненту будут приводить к ожидаемому результату (результату рендеринга или вызванным пользовательским событиям). + +Например, для компонента `Counter`, который при каждом нажатии кнопки будет увеличивать отображаемый счётчик на 1, может тестироваться с помощью симуляции клика и проверке, что в отрендренном результате значение будет увеличено на 1. Тест не заботится о том, каким образом `Counter` увеличивает значение, он сосредоточен только на входных данных и результате. + +Преимуществом этого подхода в том, что до тех пор пока интерфейс вашего компонента остаётся прежним, ваши тесты будут проходить независимо от того, как будет меняться внутренняя реализация компонента с течением времени. + +Эта тема обсуждается более подробно в [отличной презентации Matt O'Connell](http://slides.com/mattoconnell/deck#/). + +## Поверхностный рендеринг + +В модульных тестах мы обычно хотим сосредоточиться на тестируемом компоненте, как на изолированном блоке и избежать неявной проверки поведения его дочерних компонентов. + +Кроме того, для компонентов, которые содержат много дочерних компонентов, отрендеренное дерево целиком может стать очень большим. Повторяющийся рендеринг всех дочерних компонентов может замедлить наши тесты. + +`vue-test-utils` позволяет вам монтировать компонент без рендеринга его дочерних компонентов (заменяя их заглушками) с помощью метода `shallow`: + +```js +import { shallow } from '@vue/test-utils' + +const wrapper = shallow(Component) // возвращает Wrapper, содержащий примонтированный экземпляр компонента +wrapper.vm // примонтированный экземпляр Vue +``` + +## Проверка вызванных событий + +Каждая примонтированная обёртка автоматически записывает все события, вызванные на экземпляре Vue. Вы можете получить записанные события с помощью метода `wrapper.emitted()`: + +``` js +wrapper.vm.$emit('foo') +wrapper.vm.$emit('foo', 123) + +/* +`wrapper.emitted()` возвращает указанный объект: +{ + foo: [[], [123]] +} +*/ +``` + +Затем вы можете добавить проверки на основе этих данных: + +``` js +// проверка, что событие было вызвано +expect(wrapper.emitted().foo).toBeTruthy() + +// проверка, что событие вызывалось определённое число раз +expect(wrapper.emitted().foo.length).toBe(2) + +// проверка, что с событием были переданы определённые данные +expect(wrapper.emitted().foo[1]).toEqual([123]) +``` + +Вы также можете получить массив событий в порядке их вызова с помощью [`wrapper.emittedByOrder()`](../api/wrapper/emittedByOrder.md). + +## Манипулирование состоянием компонента + +Вы можете напрямую манипулировать состоянием компонента с помощью методов `setData` или `setProps` на обёртке: + +```js +wrapper.setData({ count: 10 }) + +wrapper.setProps({ foo: 'bar' }) +``` + +## Моки входных параметров + +Вы можете передать входные параметры в компонент с использованием встроенной во Vue опции `propsData`: + +```js +import { mount } from '@vue/test-utils' + +mount(Component, { + propsData: { + aProp: 'some value' + } +}) +``` + +Вы также можете обновить входные параметры на уже примонтированном компоненте с помощью метода `wrapper.setProps({})`. + +*Полный список опции можно посмотреть в [секции настроек монтирования](../api/options.md) документации.* + +## Добавление глобальных плагинов и примесей + +Некоторые из компонентов могут полагаться на функции, добавляемые глобальным плагином или примесью, к примеру `vuex` и `vue-router`. + +Если вы пишете тесты для компонентов определённого приложения, вы можете настроить одни и те же глобальные плагины и примеси один раз перед началом ваших тестов. Но в некоторых случаях, например при тестировании набора общих компонентов, которые могут использоваться в разных приложениях, гораздо лучше протестировать ваши компоненты в более изолированной конфигурации, без загрязнения глобального конструктора `Vue`. Мы можем использовать метод [`createLocalVue`](../api/createLocalVue.md) для достижения этого: + +``` js +import { createLocalVue } from '@vue/test-utils' + +// создаём расширенный конструктор `Vue` +const localVue = createLocalVue() + +// устанавливаем плагины как обычно +localVue.use(MyPlugin) + +// передаём `localVue` в настройки монтирования +mount(Component, { + localVue +}) +``` + +**Обратите внимание, что некоторые плагины, такие как Vue Router, добавляют свойства только для чтения к глобальному конструктору Vue. Это делает невозможным переустановку плагина на конструкторе localVue или добавление моков для этих свойств** + +## Создание моков инъекций + +Другая стратегия для инъекции входных параметров — просто создание их моков. Вы можете это сделать с помощью опции `mocks`: + +```js +import { mount } from '@vue/test-utils' + +const $route = { + path: '/', + hash: '', + params: { id: '123' }, + query: { q: 'hello' } +} + +mount(Component, { + mocks: { + $route // добавление мока объекта `$route` в экземпляр Vue перед монтированием компонента + } +}) +``` + +## Работа с маршрутизацией + +Поскольку маршрутизация по определению имеет отношение к общей структуре приложения и включает в себя несколько компонентов, её лучше всего тестировать с помощью интеграционных или end-to-end тестов. Для отдельных компонентов, которые используют возможности `vue-router`, вы можете создать моки с использованием упомянутых выше методов. diff --git a/docs/ru/guides/dom-events.md b/docs/ru/guides/dom-events.md new file mode 100644 index 000000000..b2751bc49 --- /dev/null +++ b/docs/ru/guides/dom-events.md @@ -0,0 +1,210 @@ +# Тестирование нажатий клавиш, мыши и других событий DOM + +## Генерация событий + +`Wrapper` предоставляет метод `trigger`. Его можно использовать для генерации событий DOM. + +```js +const wrapper = mount(MyButton) + +wrapper.trigger('click') +``` + +Вы должны помнить, что метод `find` также возвращает `Wrapper`. Предполагается, что `MyComponent` содержит кнопку, а следующий код нажимает эту кнопку. + +```js +const wrapper = mount(MyComponent) + +wrapper.find('button').trigger('click') +``` + +## Опции + +Метод `trigger` также может опционально принимать объект `options`. Свойства объекта `options` добавятся к Event. + +```js +const wrapper = mount(MyButton) + +wrapper.trigger('click', { button: 0 }) +``` + + +## Пример тестирования кнопки мыши + +**Тестируемый компонент** + +```html + + + +``` + +**Тест** + +```js +import YesNoComponent from '@/components/YesNoComponent' +import { mount } from '@vue/test-utils' +import sinon from 'sinon' + +describe('Click event', () => { + it('Нажатие на кнопке yes вызывает наш метод с аргументом "yes"', () => { + const spy = sinon.spy() + const wrapper = mount(YesNoComponent, { + propsData: { + callMe: spy + } + }) + wrapper.find('button.yes').trigger('click') + + spy.should.have.been.calledWith('yes') + }) +}) +``` + +## Пример тестирования клавиши + +**Тестируемый компонент** + +Этот компонент позволяет увеличивать/уменьшать количество с помощью различных клавиш. + +```html + + + +``` + +**Тест** + +```js +import QuantityComponent from '@/components/QuantityComponent' +import { mount } from '@vue/test-utils' + +describe('Тестирование событий клавиш', () => { + it('Quantity по умолчанию равно нулю', () => { + const wrapper = mount(QuantityComponent) + expect(wrapper.vm.quantity).toBe(0) + }) + + it('Клавиша вверх устанавливает quantity равным 1', () => { + const wrapper = mount(QuantityComponent) + wrapper.trigger('keydown.up') + expect(wrapper.vm.quantity).toBe(1) + }) + + it('Клавиша вниз уменьшает quantity на 1', () => { + const wrapper = mount(QuantityComponent) + wrapper.vm.quantity = 5 + wrapper.trigger('keydown.down') + expect(wrapper.vm.quantity).toBe(4) + }) + + it('Escape устанавливает quantity равным 0', () => { + const wrapper = mount(QuantityComponent) + wrapper.vm.quantity = 5 + wrapper.trigger('keydown.esc') + expect(wrapper.vm.quantity).toBe(0) + }) + + it('Магический символ "a" устанавливает quantity равным 13', () => { + const wrapper = mount(QuantityComponent) + wrapper.trigger('keydown', { + which: 65 + }) + expect(wrapper.vm.quantity).toBe(13) + }) +}) + +``` + +**Ограничения** + +Имя модификатора после точки `keydown.up` преобразуется в `keyCode`. Это поддерживается для следующих имён: + +| key name | key code | +| --- | --- | +| enter | 13 | +| esc | 27 | +| tab | 9 | +| space | 32 | +| delete | 46 | +| backspace | 8 | +| insert | 45 | +| up | 38 | +| down | 40 | +| left | 37 | +| right | 39 | +| end | 35 | +| home | 36 | +| pageup | 33 | +| pagedown | 34 | + +## Важно + +`vue-test-utils` генерирует событие синхронно. Следовательно, `Vue.nextTick` не требуется. diff --git a/docs/ru/guides/getting-started.md b/docs/ru/guides/getting-started.md new file mode 100644 index 000000000..151fd1795 --- /dev/null +++ b/docs/ru/guides/getting-started.md @@ -0,0 +1,144 @@ +# Введение + +## Настройка + +Для быстрого старта работы с `vue-test-utils`, клонируйте наш демонстрационный репозиторий с базовыми настройками и установите зависимости: + +``` bash +git clone https://github.com/vuejs/vue-test-utils-getting-started +cd vue-test-utils-getting-started +npm install +``` + +Вы увидите, что проект содержит простой компонент `counter.js`: + +```js +// counter.js + +export default { + template: ` +
+ {{ count }} + +
+ `, + + data () { + return { + count: 0 + } + }, + + methods: { + increment () { + this.count++ + } + } +} +``` + +### Монтирование компонентов + +`vue-test-utils` тестирует компоненты Vue монтируя их изолированно, создавая моки необходимых входных данных (входные параметры, инъекции и пользовательские события) и выполняя проверки над результатом (результат рендеринга, вызванные пользовательские события). + +Примонтированные компоненты возвращаются внутри [Wrapper](../api/wrapper/), который предоставляет множество удобных методов для манипулирования, перемещения и различных запросов для экземпляра компонента Vue. + +Вы можете создавать wrapper с помощью метода `mount`. Давайте создадим файл `test.js`: + +```js +// test.js + +// Импортируем метод `mount()` из `vue-test-utils` +// и компонент, который хотим протестировать +import { mount } from '@vue/test-utils' +import Counter from './counter' + +// Теперь монтируем компонент и у нас появляется wrapper +const wrapper = mount(Counter) + +// Вы можете получить доступ к экземпляру Vue через `wrapper.vm` +const vm = wrapper.vm + +// Чтобы изучить wrapper подробнее, просто выведите его в консоль +// и ваши приключения с `vue-test-utils` начнутся +console.log(wrapper) +``` + +### Тестирование отрендеренного HTML компонента + +Теперь, когда у нас есть wrapper, первой вещью, которую мы можем захотеть проверить что отрендеренный HTML компонента соответствует нашим ожиданиям. + +```js +import { mount } from '@vue/test-utils' +import Counter from './counter' + +describe('Компонент Counter', () => { + // Теперь монтируем компонент и получаем wrapper + const wrapper = mount(Counter) + + it('отображает корректную разметку', () => { + expect(wrapper.html()).toContain('0') + }) + + // также легко проверить наличие других элементов + it('имеет кнопку', () => { + expect(wrapper.contains('button')).toBe(true) + }) +}) +``` + +Теперь запустите тесты командой `npm test`. Вы должны увидеть, что все тесты проходят успешно. + +### Симуляция пользовательских действий + +Наш счётчик должен увеличивать значение, когда пользователь нажимает кнопку. Чтобы симулировать это поведение, нам необходимо сначала получить кнопку с помощью `wrapper.find()`, который возвращает **wrapper для элемента кнопки**. Мы можем симулировать клик с помощью вызова `.trigger()` на wrapper кнопки: + +```js +it('нажатие кнопки должно увеличивать счётчик', () => { + expect(wrapper.vm.count).toBe(0) + const button = wrapper.find('button') + button.trigger('click') + expect(wrapper.vm.count).toBe(1) +}) +``` + +### Что делать с `nextTick`? + +Vue собирает пачку предстоящих обновлений DOM и применяет их асинхронно для избежания ненужных повторных рендерингов, вызываемых множественными изменениями данных. Вот почему на практике на часто приходится использовать `Vue.nextTick` для ожидания, пока Vue не выполнит фактическое обновление DOM после того, как мы инициируем некоторое изменение состояния. + +Для упрощения работы, `vue-test-utils` применяет все обновления синхронно, поэтому вам не потребуется использовать `Vue.nextTick` для ожидания обновления DOM в ваших тестах. + +*Примечание: `nextTick` по-прежнему необходим, когда вам нужно явно форсировать цикл событий, для таких операций как асинхронные обратные вызовы или разрешение промисов.* + +Если вам всё ещё нужно использовать `nextTick` в ваших тестовых файлах, имейте ввиду, что любые ошибки, выброшенные внутри него, могут не быть отловлены вашей программой для запуска тестов, поскольку внутри он реализован на Promise. Существует два подхода исправления этого: либо вы можете установить коллбэк `done` как глобальный обработчик ошибок Vue в начале теста, либо вы можете вызывать `nextTick` без аргумента и вернуть его как Promise: + +```js +// эта ошибка не будет отловлена +it('ошибка не будет отслеживаться', (done) => { + Vue.nextTick(() => { + expect(true).toBe(false) + done() + }) +}) + +// два следующих теста будут работать как ожидается +it('должен отлавливать ошибку с использованием done', (done) => { + Vue.config.errorHandler = done + Vue.nextTick(() => { + expect(true).toBe(false) + done() + }) +}) + +it('должен отлавливать ошибку с использованием promise', () => { + return Vue.nextTick() + .then(function () { + expect(true).toBe(false) + }) +}) +``` + +## Что дальше + +- Интегрируйте `vue-test-utils` в ваш проект выбрав [программу для запуска тестов](./choosing-a-test-runner.md). +- Прочитайте больше об [общих техниках и советах при написании тестов](./common-tips.md). diff --git a/docs/ru/guides/testing-SFCs-with-jest.md b/docs/ru/guides/testing-SFCs-with-jest.md new file mode 100644 index 000000000..b9458eea1 --- /dev/null +++ b/docs/ru/guides/testing-SFCs-with-jest.md @@ -0,0 +1,212 @@ +# Тестирование однофайловых компонентов с Jest + +> Пример проекта для этой конфигурации доступен на [GitHub](https://github.com/vuejs/vue-test-utils-jest-example). + +Jest — это программа для запуска тестов, разработанная Facebook, направленная на предоставление функционального решения для модульного тестирования. Вы можете узнать больше о Jest в [официальной документации](https://facebook.github.io/jest/). + +## Установка Jest + +Предположим, что вы начинаете с конфигурации, где правильно настроены webpack, vue-loader и Babel — например, развёрнутый шаблон `webpack-simple` с помощью `vue-cli`. + +Первым делом нам необходимо установить Jest и `vue-test-utils`: + +```bash +$ npm install --save-dev jest vue-test-utils +``` + +Затем, необходимо указать псевдоним для запуска тестов в нашем `package.json`. + +```json +// package.json +{ + "scripts": { + "test": "jest" + } +} +``` + +## Обработка однофайловых компонентов с Jest + +Чтобы научить Jest как обрабатывать `*.vue` файлы, нам необходимо установить и настроить пре-процессор `vue-jest`: + +``` bash +npm install --save-dev vue-jest +``` + +Теперь, создадим секцию `jest` в файле `package.json`: + +``` json +{ + // ... + "jest": { + "moduleFileExtensions": [ + "js", + "json", + // сообщаем Jest что необходимо обрабатывать `*.vue` файлы + "vue" + ], + "transform": { + // обрабатываем `*.vue` файлы с помощью `vue-jest` + ".*\\.(vue)$": "/node_modules/vue-jest" + }, + "mapCoverage": true + } +} +``` + +> **Примечание:** `vue-jest` в настоящее время не поддерживает все возможности `vue-loader`, например пользовательские блоки и загрузку стилей. Кроме того, некоторые функции, специфичные для webpack, такие как code-splitting, также не поддерживаются. Чтобы использовать их прочитайте руководство по [тестированию однофайловых компонентов с Mocha + webpack](./testing-SFCs-with-mocha-webpack.md). + +## Обработка псевдонимов webpack + +Если вы используете псевдонимы в конфигурации webpack, например когда `@` ссылается на путь `/src`, вам также нужно добавить соответствующую конфигурацию для Jest, используя опцию `moduleNameMapper`: + +``` json +{ + // ... + "jest": { + // ... + // добавление поддержки псевдонима @ -> src в исходном коде + "moduleNameMapper": { + "^@/(.*)$": "/src/$1" + } + } +} +``` + +## Конфигурация Babel для Jest + + +Хотя последние версии Node уже поддерживают большинство функций ES2015, вы всё равно можете использовать синтаксис ES-модулей и stage-x функции в ваших тестах. Для этого нужно установить `babel-jest`: + +``` bash +npm install --save-dev babel-jest +``` + +Затем мы должны сообщить Jest обрабатывать файлы тестов с JavaScript с помощью `babel-jest`, добавив запись `jest.transform` в `package.json`: + +``` json +{ + // ... + "jest": { + // ... + "transform": { + // ... + // обрабатывать js с помощью `babel-jest` + "^.+\\.js$": "/node_modules/babel-jest" + }, + // ... + } +} +``` + +> По умолчанию `babel-jest` автоматически настраивается по установке. Однако, поскольку мы явно добавили преобразование файлов `*.vue`, нам теперь нужно также настроить `babel-jest`. + +Предполагая использование `babel-preset-env` с webpack, конфигурация Babel по умолчанию отключает транспиляцию ES-модулей, потому что webpack уже знает как обрабатывать ES-модули. Однако нам нужно включить его для наших тестов, потому что тесты Jest запускаются непосредственно в Node. + +Кроме того, мы можем указать `babel-preset-env` в качестве цели используемую нами версию Node. Это пропустит транспиляцию ненужных функций и ускорит загрузку тестов. + +Чтобы применить эти параметры только для тестов, поместите их в отдельную конфигурацию в `env.test` (это будет автоматически обработано `babel-jest`). + +Пример `.babelrc`: + +``` json +{ + "presets": [ + ["env", { "modules": false }] + ], + "env": { + "test": { + "presets": [ + ["env", { "targets": { "node": "current" }}] + ] + } + } +} +``` + +## Тестирование моментальными снимками + +Вы можете использовать [`vue-server-renderer`](https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer) для рендеринга компонента в строку, чтобы его можно было сохранить в качестве снимка для [тестирования моментальными снимками в Jest](https://facebook.github.io/jest/docs/en/snapshot-testing.html). + +Результат рендеринга `vue-server-renderer` включает в себя несколько атрибутов, специфичных для SSR, и игнорирует пробелы, что затрудняет сравнивать diff. Мы можем улучшить сохранённый снимок с помощью специального сериализатора: + +``` bash +npm install --save-dev jest-serializer-vue +``` + +Затем добавьте конфигурацию в `package.json`: + +``` json +{ + // ... + "jest": { + // ... + // сериализатор для снимков + "snapshotSerializers": [ + "/node_modules/jest-serializer-vue" + ] + } +} +``` + +## Расположение файлов тестов + +По умолчанию Jest будет рекурсивно выбирать все файлы с расширением `.spec.js` или `.test.js` во всём проекте. Если это поведение не соответствует вашим потребностям, то возможно [изменить `testRegex`](https://facebook.github.io/jest/docs/en/configuration.html#testregex-string) в секции конфигурации в файле `package.json`. + +Jest рекомендует создать каталог `__tests__` рядом с тестируемым кодом, но не стесняйтесь структурировать ваши тесты по своему усмотрению. Просто остерегайтесь того, что Jest создаст каталог `__snapshots__` рядом с тестовыми файлами, который необходим для тестирования с помощью моментальных снимков. + +## Покрытие кода (Coverage) + +Jest может быть использован для генерации отчётов о покрытии кода в нескольких форматах. Ниже приведён простой пример для начала: + +Расширьте вашу конфигурацию `jest` (обычно расположенную в `package.json` или `jest.config.js`) с помощью опции [collectCoverage](https://facebook.github.io/jest/docs/en/configuration.html#collectcoverage-boolean), и затем добавьте массив [collectCoverageFrom](https://facebook.github.io/jest/docs/en/configuration.html#collectcoveragefrom-array) для определения файлов, для которых требуется собирать информацию о покрытии. Вы также можете установить [mapCoverage](https://facebook.github.io/jest/docs/en/configuration.html#mapcoverage-boolean) в значение `true`, для более аккуратного сбора информации о покрытии. + +```json +{ + "jest": { + // ... + "collectCoverage": true, + "collectCoverageFrom": [ + "**/*.{js,vue}", + "!**/node_modules/**" + ], + "mapCoverage": true + } +} +``` + +Это включит отчёты о покрытии с использованием [стандартных отчётов о покрытии](https://facebook.github.io/jest/docs/en/configuration.html#coveragereporters-array-string). Вы можете настроить их с помощью опции `coverageReporters`: + +```json +{ + "jest": { + // ... + "coverageReporters": ["html", "text-summary"] + } +} +``` + +Дополнительную информацию можно найти в [документации по конфигурации Jest](https://facebook.github.io/jest/docs/en/configuration.html#collectcoverage-boolean), где вы можете найти параметры для пороговых значений покрытия, каталоги вывода данных и т.д. + +## Пример спецификации + +Если вы знакомы с Jasmine, то вы должны чувствовать себя как дома с [проверочным API](https://facebook.github.io/jest/docs/en/expect.html#content) Jest: + +```js +import { mount } from '@vue/test-utils' +import Component from './component' + +describe('Component', () => { + test('является экземпляром Vue', () => { + const wrapper = mount(Component) + expect(wrapper.isVueInstance()).toBeTruthy() + }) +}) +``` + +## Ресурсы + +- [Пример проекта для этой конфигурации](https://github.com/vuejs/vue-test-utils-jest-example) +- [Примеры и слайды с Vue Conf 2017](https://github.com/codebryo/vue-testing-with-jest-conf17) +- [Jest](https://facebook.github.io/jest/) +- [Babel preset env](https://github.com/babel/babel-preset-env) diff --git a/docs/ru/guides/testing-SFCs-with-mocha-webpack.md b/docs/ru/guides/testing-SFCs-with-mocha-webpack.md new file mode 100644 index 000000000..dc8a8b88c --- /dev/null +++ b/docs/ru/guides/testing-SFCs-with-mocha-webpack.md @@ -0,0 +1,184 @@ +# Тестирование однофайловых компонентов с Mocha + webpack + +> Пример проекта для этой конфигурации доступен на [GitHub](https://github.com/vuejs/vue-test-utils-mocha-webpack-example). + +Другая стратегия тестирования однофайловых компонентов заключается в компиляции всех наших тестов с помощью webpack, а затем программой для запуска тестов. Преимущество такого подхода заключается в том, что он даёт нам полную поддержку всех функций webpack и `vue-loader`, поэтому нам не нужно идти на компромиссы в нашем исходном коде. + +Технически, вы можете использовать любую программу для запуска тестов, которая вам нравится, и вручную соединять вещи, но мы нашли [`mocha-webpack`](https://github.com/zinserjan/mocha-webpack) как очень удобный способ для реализации этой задачи. + +## Настройка `mocha-webpack` + +Мы предположим, что вы начинаете с настройки, когда уже есть правильно настроенные webpack, vue-loader и Babel — например используя шаблон `webpack-simple`, развёрнутый с помощью `vue-cli`. + +Первое, что нужно сделать, это установить тестовые зависимости: + +``` bash +npm install --save-dev @vue/test-utils mocha mocha-webpack +``` + +Затем мы должны указать скрипт test в нашем `package.json`. + +```json +// package.json +{ + "scripts": { + "test": "mocha-webpack --webpack-config webpack.config.js --require test/setup.js test/**/*.spec.js" + } +} +``` + +Несколько вещей, о том что мы сделали: + +- Флаг `--webpack-config` указывает конфигурационный файл webpack для использования в тестах. В большинстве случаев это будут идентичная конфигурация, используемой в проекте, с одной небольшой доработкой. Мы поговорим об этом позднее. + +- Флаг `--require` гарантирует, что файл `test/setup.js` будет запущен перед любыми тестами, в котором мы можем настроить для наших тестов глобальное окружение, в котором они будут запускаться. + +- Последний аргумент — это шаблон для тестовых файлов, которые будут включены в тестовую сборку. + +### Дополнительная конфигурация webpack + +#### Вынесение внешних NPM-зависимостей + +В наших тестах мы, скорее всего, импортируем ряд NPM-зависимостей — некоторые из этих модулей могут быть написаны не для использования в браузере и просто не смогут быть корректно добавлены в сборку webpack. Другой плюс в том, что извлечение внешних зависимостей значительно улучшит скорость загрузки тестов. Мы можем вынести все NPM-зависимости с помощью `webpack-node-externals`: + +```js +// webpack.config.js +const nodeExternals = require('webpack-node-externals') + +module.exports = { + // ... + externals: [nodeExternals()] +} +``` + +#### Source Maps + +Source maps должны быть встроены для использования в `mocha-webpack`. Рекомендуемая конфигурация: + +``` js +module.exports = { + // ... + devtool: 'inline-cheap-module-source-map' +} +``` + +При отладке через IDE рекомендуется также добавить следующее: + +``` js +module.exports = { + // ... + output: { + // ... + // использовать абсолютные пути в sourcemaps (важно для отладки через IDE) + devtoolModuleFilenameTemplate: '[absolute-resource-path]', + devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]' + } +} +``` + +### Настройка браузерного окружения + +`vue-test-utils` требует браузерного окружения для запуска. Мы можем симулировать его в Node используя `jsdom-global`: + +```bash +npm install --save-dev jsdom jsdom-global +``` + +Затем в `test/setup.js`: + +``` js +require('jsdom-global')() +``` + +Это добавит браузерное окружение в Node, таким образом `vue-test-utils` сможет корректно запуститься. + +### Выбор библиотеки утверждений + +[Chai](http://chaijs.com/) — популярная библиотека утверждений, которая обычно используется вместе с Mocha. Вы также можете воспользоваться [Sinon](http://sinonjs.org/) для создания шпионов и заглушек. + +В качестве альтернативы вы можете использовать `expect`, который является частью Jest и реализует [точно такой же API](http://facebook.github.io/jest/docs/en/expect.html#content) в документации Jest. + +Мы будем использовать `expect` здесь и сделаем его глобально доступным, чтобы нам не приходилось импортировать его в каждом тесте: + +``` bash +npm install --save-dev expect +``` + +Затем в `test/setup.js`: + +``` js +require('jsdom-global')() + +global.expect = require('expect') +``` + +### Оптимизация Babel для тестов + +Обратите внимание, что мы используем `babel-loader` для обработки JavaScript. У вас уже должен быть настроен Babel, если вы используете его в своём приложении, через файл `.babelrc`. Здесь `babel-loader` будет автоматически использовать тот же файл конфигурации. + +Следует отметить, что если вы используете Node 6+, которая уже поддерживает большинство функций ES2015, вы можете настроить отдельную [опцию env](https://babeljs.io/docs/usage/babelrc/#env-option) Babel, которая будет транспилировать только те функции, которые ещё не поддерживаются в используемой версии Node (например, `stage-2` или поддержку синтаксиса flow, и т.п.). + +### Добавление теста + +Создайте файл в `src` названный `Counter.vue`: + +``` html + + + +``` + +И создайте файл теста, названный `test/Counter.spec.js` со следующим кодом: + +```js +import { shallow } from '@vue/test-utils' +import Counter from '../src/Counter.vue' + +describe('Counter.vue', () => { + it('увеличивает счётчик по нажатию кнопки', () => { + const wrapper = shallow(Counter) + wrapper.find('button').trigger('click') + expect(wrapper.find('div').text()).toMatch('1') + }) +}) +``` + +И теперь мы можем запустить тест: + +``` +npm run unit +``` + +Ура, мы запустили наши тесты! + +### Покрытие кода (Coverage) + +Для настройки покрытия кода в mocha-webpack, следуйте [инструкции по настройке покрытия кода mocha-webpack](https://github.com/zinserjan/mocha-webpack/blob/master/docs/guides/code-coverage.md). + +### Ресурсы + +- [Пример проекта для этой конфигурации](https://github.com/vuejs/vue-test-utils-mocha-webpack-example) +- [Mocha](https://mochajs.org/) +- [mocha-webpack](http://zinserjan.github.io/mocha-webpack/) +- [Chai](http://chaijs.com/) +- [Sinon](http://sinonjs.org/) +- [jest/expect](http://facebook.github.io/jest/docs/en/expect.html#content) diff --git a/docs/ru/guides/testing-async-components.md b/docs/ru/guides/testing-async-components.md new file mode 100644 index 000000000..dc481fbc2 --- /dev/null +++ b/docs/ru/guides/testing-async-components.md @@ -0,0 +1,97 @@ +# Тестирование асинхронной логики + +Чтобы упростить тестирование, `vue-test-utils` применяет обновления DOM _синхронно_. Однако, есть некоторые тонкости, когда вам необходимо протестировать компонент с асинхронным поведением, таким как коллбэки или промисы. + +Одними из самых распространённых поведений являются запросы к API и действия Vuex. В примерах ниже будет показано как протестировать метод, который делает запрос к API. В этом примере используется Jest для запуска тестов и мок для HTTP-библиотеки `axios`. Подробнее о использовании моков в Jest можно прочитать [здесь](https://facebook.github.io/jest/docs/en/manual-mocks.html#content). + +Реализация мока для `axios` выглядит так: + +``` js +export default { + get: () => new Promise(resolve => { + resolve({ data: 'value' }) + }) +} +``` + +Компонент ниже делает вызов к API при нажатии кнопки и сохраняет полученный ответ в `value`. + +``` html + + + +``` + +Тест можно написать следующим образом: + +``` js +import { shallow } from '@vue/test-utils' +import Foo from './Foo' +jest.mock('axios') + +test('Foo', () => { + it('делает асинхронный запрос при нажатии кнопки', () => { + const wrapper = shallow(Foo) + wrapper.find('button').trigger('click') + expect(wrapper.vm.value).toBe('value') + }) +}) +``` + +В настоящее время этот тест не будет успешно проходить, потому что проверка значения вызывается до разрешения промиса `fetchResults`. Большинство библиотек для модульного тестирования предоставляют коллбэк, чтобы предоставить возможность определять когда тест должен будет завершаться. Jest и Mocha используют `done`. Мы можем использовать `done` в комбинации с `$nextTick` или `setTimeout`, чтобы гарантировать, что любые промисы будут разрешены перед проверками. + +``` js +test('Foo', () => { + it('делает асинхронный запрос при нажатии кнопки', (done) => { + const wrapper = shallow(Foo) + wrapper.find('button').trigger('click') + wrapper.vm.$nextTick(() => { + expect(wrapper.vm.value).toBe('value') + done() + }) + }) +}) +``` + +Необходимость `$nextTick` или `setTimeout` требуется для прохождения теста, потому что очередь микрозадач, в которой обрабатываются промисы, обрабатывается до очереди задач, где обрабатываются `$nextTick` и `setTimeout`. Это означает, что к моменту запуска `$nexTick` и `setTimeout`, будут выполнены любые коллбэки промисов. См. [здесь](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) для более подробного объяснения. + +Другое решение — использовать `async` функцию и npm-пакет `flush-promises`. `flush-promises` сбрасывает все ожидаемые промисы. Вы можете использовать `await` вызов для `flushPromises` чтобы очистить все ожидаемые промисы и улучшить читаемость вашего теста. + +Обновлённый тест будет выглядеть так: + +``` js +import { shallow } from '@vue/test-utils' +import flushPromises from 'flush-promises' +import Foo from './Foo' +jest.mock('axios') + +test('Foo', () => { + it('делает асинхронный запрос при нажатии кнопки', async () => { + const wrapper = shallow(Foo) + wrapper.find('button').trigger('click') + await flushPromises() + expect(wrapper.vm.value).toBe('value') + }) +}) +``` + +Подобная техника может применяться и для действий Vuex, которые возвращают promise по умолчанию. diff --git a/docs/ru/guides/using-with-vue-router.md b/docs/ru/guides/using-with-vue-router.md new file mode 100644 index 000000000..2e35c9ca0 --- /dev/null +++ b/docs/ru/guides/using-with-vue-router.md @@ -0,0 +1,79 @@ +# Использование с Vue Router + +## Установка Vue Router в тестах + +Вы никогда не должны устанавливать Vue Router в базовый конструктор Vue в тестах. Установка Vue Router добавляет `$route` и `$router` как свойства только для чтения на прототипе Vue. + +Чтобы этого избежать, мы можем создать localVue и установить Vue Router на него. + +```js +import { shallow, createLocalVue } from '@vue/test-utils' +import VueRouter from 'vue-router' + +const localVue = createLocalVue() +localVue.use(VueRouter) +const router = new VueRouter() + +shallow(Component, { + localVue, + router +}) +``` + +## Тестирование компонентов использующих `router-link` или `router-view` + +Когда вы устанавливаете Vue Router, регистрируются глобальные компоненты `router-link` и `router-view`. Это означает, что мы можем использовать их в любом месте нашего приложения без необходимости импортировать их. + +Когда мы запускаем тесты, нам нужно сделать эти компоненты vue-router доступными для компонента, который мы монтируем. Есть два способа сделать это. + +### Использование заглушек (stubs) + +```js +import { shallow } from '@vue/test-utils' + +shallow(Component, { + stubs: ['router-link', 'router-view'] +}) +``` + +### Установка Vue Router с помощью localVue + +```js +import { shallow, createLocalVue } from '@vue/test-utils' +import VueRouter from 'vue-router' + +const localVue = createLocalVue() +localVue.use(VueRouter) + +shallow(Component, { + localVue +}) +``` + +## Создание моков `$route` и `$router` + +Иногда вам может потребоваться протестировать, что компонент что-то делает с параметрами объектов `$route` и `$router`. Для этого вы можете передавать пользовательские моки в экземпляр Vue. + +```js +import { shallow } from '@vue/test-utils' + +const $route = { + path: '/some/path' +} + +const wrapper = shallow(Component, { + mocks: { + $route + } +}) + +wrapper.vm.$route.path // /some/path +``` + +## Общие ошибки + +Установка Vue Router добавляет `$route` и `$router` в качестве свойств только для чтения на прототипе Vue. + +Это означет, что любые будущие тесты, которые попытаются сделать мок `$route` или `$router` потерпят неудачу. + +Для избежания этого никогда не устанавливайте Vue Router глобально при запуске тестов; используйте localVue как было показано выше. diff --git a/docs/ru/guides/using-with-vuex.md b/docs/ru/guides/using-with-vuex.md new file mode 100644 index 000000000..198a4e28b --- /dev/null +++ b/docs/ru/guides/using-with-vuex.md @@ -0,0 +1,265 @@ +# Использование с Vuex + +В этом руководстве мы рассмотрим как тестировать Vuex в компонентах с `vue-test-utils`. + +## Создание моков для действий + +Давайте посмотрим на часть кода. + +Это компонент который мы хотим протестировать. Он вызывает действие Vuex. + +``` html + + + +``` + +Для целей этого теста нам всё равно, что делает действие или как выглядит структура хранилища. Мы должны просто узнать, что это действие вызывается когда должно, и что оно вызывается с ожидаемым значением. + +Чтобы протестировать это, нам нужно передать мок хранилища в Vue, когда мы отделяем наш компонент. + +Вместо передачи хранилища в базовый конструктор Vue, мы можем передать его в [localVue](../api/options.md#localvue). localVue — это изолированный конструктор Vue, в который мы можем вносить изменения без влияния на глобальный конструктор Vue. + +Давайте посмотрим, как это выглядит: + +``` js +import { shallow, createLocalVue } from '@vue/test-utils' +import Vuex from 'vuex' +import Actions from '../../../src/components/Actions' + +const localVue = createLocalVue() + +localVue.use(Vuex) + +describe('Actions.vue', () => { + let actions + let store + + beforeEach(() => { + actions = { + actionClick: jest.fn(), + actionInput: jest.fn() + } + store = new Vuex.Store({ + state: {}, + actions + }) + }) + + it('вызывает действие хранилища "actionInput" когда значение поля "input" и было событие "input"', () => { + const wrapper = shallow(Actions, { store, localVue }) + const input = wrapper.find('input') + input.element.value = 'input' + input.trigger('input') + expect(actions.actionInput).toHaveBeenCalled() + }) + + it('не вызывает действие хранилища "actionInput" когда значение поля отлично от "input" и было событие "input"', () => { + const wrapper = shallow(Actions, { store, localVue }) + const input = wrapper.find('input') + input.element.value = 'not input' + input.trigger('input') + expect(actions.actionInput).not.toHaveBeenCalled() + }) + + it('вызывает действие хранилища "actionClick" по нажатию кнопки', () => { + const wrapper = shallow(Actions, { store, localVue }) + wrapper.find('button').trigger('click') + expect(actions.actionClick).toHaveBeenCalled() + }) +}) +``` + +Что тут происходит? Сначала мы говорим Vue использовать Vuex с помощью метода `localVue.use`. Это всего лишь обёртка вокруг `Vue.use`. + +Затем мы создаём мок хранилища вызовом `new Vuex.store` с нашими заготовленными значениями. Мы передаём ему только действия, так как это всё, что нам необходимо. + +Действия реализуются с помощью [mock-функций jest](https://facebook.github.io/jest/docs/en/mock-functions.html). Эти mock-функции предоставляют нам методы для проверки, вызывались ли действия или нет. + +Затем мы можем проверить в наших тестах, что заглушка действия была вызвана когда ожидалось. + +Теперь способ, которым мы определяем наше хранилище выглядит немного необычным для вас. + +Мы используем `beforeEach`, чтобы убедиться, что у нас есть чистое хранилище перед каждым тестом. `beforeEach` — это хук в mocha, который вызывается перед каждым тестом. В нашем тесте мы переназначаем значения переменных хранилища. Если бы мы этого не сделали, mock-функции нужно было бы автоматически сбрасывать. Это также позволяет нам изменять состояние в наших тестах, не влияя на последующие тесты. + +Самое важно, что следует отметить в этом тесте — то что **мы создаём мок хранилища Vuex и затем передаём его в `vue-test-utils`**. + +Отлично, теперь мы можем создавать моки действий, давайте посмотрим на создание моков для геттеров. + +## Создание моков для геттеров + +``` html + + + +``` + +Это довольно простой компонент. Он отображает результат геттеров `clicks` и `inputValue`. Опять же, нас не волнует что возвращают эти геттеры — только то, что их результат будет корректно отображён. + +Давайте посмотрим на тест: + +``` js +import { shallow, createLocalVue } from '@vue/test-utils' +import Vuex from 'vuex' +import Getters from '../../../src/components/Getters' + +const localVue = createLocalVue() + +localVue.use(Vuex) + +describe('Getters.vue', () => { + let getters + let store + + beforeEach(() => { + getters = { + clicks: () => 2, + inputValue: () => 'input' + } + + store = new Vuex.Store({ + getters + }) + }) + + it('Отображает "state.inputValue" в первом теге p', () => { + const wrapper = shallow(Getters, { store, localVue }) + const p = wrapper.find('p') + expect(p.text()).toBe(getters.inputValue()) + }) + + it('Отображает "state.clicks" во втором теге p', () => { + const wrapper = shallow(Getters, { store, localVue }) + const p = wrapper.findAll('p').at(1) + expect(p.text()).toBe(getters.clicks().toString()) + }) +}) +``` + +Этот тест очень похож на тест действий. Мы создаём мок хранилища перед каждым тестом, передаём его в качестве опции когда вызываем `shallow`, и проверяем что значение вернувшееся из мока-геттера отображается. + +Это здорово, но что, если мы хотим проверить, что наши геттеры возвращают правильную часть нашего состояния? + +## Создание моков с модулями + +[Модули](https://vuex.vuejs.org/ru/modules.html) полезны для разделения нашего хранилища на управляемые части. Они также экспортируют геттеры. Мы можем использовать их в наших тестах. + +Давайте взглянем на наш компонент: + +``` html + + + +``` + +Простой компонент, который содержит одно действие и один геттер. + +И тест: + +``` js +import { shallow, createLocalVue } from '@vue/test-utils' +import Vuex from 'vuex' +import Modules from '../../../src/components/Modules' +import module from '../../../src/store/module' + +const localVue = createLocalVue() + +localVue.use(Vuex) + +describe('Modules.vue', () => { + let actions + let state + let store + + beforeEach(() => { + state = { + module: { + clicks: 2 + } + } + + actions = { + moduleActionClick: jest.fn() + } + + store = new Vuex.Store({ + state, + actions, + getters: module.getters + }) + }) + + it('вызывает действие "moduleActionClick" при нажатии кнопки', () => { + const wrapper = shallow(Modules, { store, localVue }) + const button = wrapper.find('button') + button.trigger('click') + expect(actions.moduleActionClick).toHaveBeenCalled() + }) + + it('отображает "state.inputValue" в первом теге p', () => { + const wrapper = shallow(Modules, { store, localVue }) + const p = wrapper.find('p') + expect(p.text()).toBe(state.module.clicks.toString()) + }) +}) +``` + +### Ресурсы + +- [Пример проекта для этого руководства](https://github.com/eddyerburgh/vue-test-utils-vuex-example) +- [`localVue`](../api/options.md#localvue) +- [`createLocalVue`](../api/createLocalVue.md) From ecebea9b9ddc829f156c95f877b483a47e263036 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 11 Jun 2018 16:51:06 +0300 Subject: [PATCH 02/32] Russian docs: video link for common tips sync with https://github.com/vuejs/vue-test-utils/commit/c0b2101f75b80e1dd5691656d0929085d5adb886#diff-e3e2a9bfd88566b05001b02a3f51d286 --- docs/ru/guides/common-tips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/guides/common-tips.md b/docs/ru/guides/common-tips.md index 173ffd9af..24b229d7b 100644 --- a/docs/ru/guides/common-tips.md +++ b/docs/ru/guides/common-tips.md @@ -10,7 +10,7 @@ Преимуществом этого подхода в том, что до тех пор пока интерфейс вашего компонента остаётся прежним, ваши тесты будут проходить независимо от того, как будет меняться внутренняя реализация компонента с течением времени. -Эта тема обсуждается более подробно в [отличной презентации Matt O'Connell](http://slides.com/mattoconnell/deck#/). +Эта тема обсуждается более подробно в [отличной презентации Matt O'Connell](https://www.youtube.com/watch?v=OIpfWTThrK8). ## Поверхностный рендеринг From 88f2232bf74c7e8a9c2b57a8098579c41716fa6b Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 11 Jun 2018 16:52:42 +0300 Subject: [PATCH 03/32] Russian docs: overwrite arrays in setData sync with https://github.com/vuejs/vue-test-utils/commit/032a7a4e7910ff7c8f8c659a90ff921cfd478d0f#diff-e3e2a9bfd88566b05001b02a3f51d286 --- docs/ru/api/wrapper/setData.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/ru/api/wrapper/setData.md b/docs/ru/api/wrapper/setData.md index f5e9f76bc..4e077015b 100644 --- a/docs/ru/api/wrapper/setData.md +++ b/docs/ru/api/wrapper/setData.md @@ -1,9 +1,12 @@ # setData(data) -Устанавливает данные `Wrapper` `vm` и выполняет принудительное обновление. +Устанавливает данные `Wrapper` `vm`. **Обратите внимание, что `Wrapper` должен содержать экземпляр Vue.** +setData работает путём слияния существующих свойств, за исключением массивов, которые перезаписываются. + + - **Принимает:** - `{Object} data` From 41142a25d03dab923e138dd1cab42857faddf37f Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 11 Jun 2018 16:54:55 +0300 Subject: [PATCH 04/32] Russian docs: remove phantomjs limitation sync with https://github.com/vuejs/vue-test-utils/commit/e9f3305efae71b3df874a7debedc4963161ed922#diff-e3e2a9bfd88566b05001b02a3f51d286 --- docs/ru/api/options.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/ru/api/options.md b/docs/ru/api/options.md index 9152c191c..6895016f3 100644 --- a/docs/ru/api/options.md +++ b/docs/ru/api/options.md @@ -59,14 +59,6 @@ const wrapper = shallow(Component, { expect(wrapper.find('div')).toBe(true) ``` -#### Передача текста - -Вы можете передать текст в `slots`. -Для этого есть одно ограничение. - -Это не поддерживается PhantomJS. -Используйте [Puppeteer](https://github.com/karma-runner/karma-chrome-launcher#headless-chromium-with-puppeteer). - ### `stubs` - Тип: `{ [name: string]: Component | boolean } | Array` From 357aed601d2d694797c55a974191c4694ce073da Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 11 Jun 2018 18:54:40 +0300 Subject: [PATCH 05/32] Russian translation: actualize docs --- docs/ru/README.md | 18 +- docs/ru/SUMMARY.md | 66 ------- docs/ru/api/README.md | 61 +----- docs/ru/api/components/README.md | 6 +- docs/ru/api/components/RouterLinkStub.md | 20 ++ docs/ru/api/config.md | 74 ++++++- docs/ru/api/mount.md | 2 +- docs/ru/api/options.md | 44 ++++- docs/ru/api/render.md | 103 ++++++++++ docs/ru/api/renderToString.md | 101 ++++++++++ docs/ru/api/{shallow.md => shallowMount.md} | 22 +-- docs/ru/api/wrapper-array/README.md | 23 ++- docs/ru/api/wrapper-array/filter.md | 22 +++ docs/ru/api/wrapper-array/isVisible.md | 21 ++ docs/ru/api/wrapper/README.md | 56 +++++- docs/ru/api/wrapper/isVisible.md | 21 ++ docs/ru/api/wrapper/setChecked.md | 17 ++ docs/ru/api/wrapper/setSelected.md | 19 ++ docs/ru/api/wrapper/setValue.md | 17 ++ docs/ru/guides/README.md | 18 +- docs/ru/guides/common-tips.md | 4 + docs/ru/guides/testing-SFCs-with-karma.md | 202 ++++++++++++++++++++ 22 files changed, 770 insertions(+), 167 deletions(-) delete mode 100644 docs/ru/SUMMARY.md create mode 100644 docs/ru/api/components/RouterLinkStub.md create mode 100644 docs/ru/api/render.md create mode 100644 docs/ru/api/renderToString.md rename docs/ru/api/{shallow.md => shallowMount.md} (82%) create mode 100644 docs/ru/api/wrapper-array/filter.md create mode 100644 docs/ru/api/wrapper-array/isVisible.md create mode 100644 docs/ru/api/wrapper/isVisible.md create mode 100644 docs/ru/api/wrapper/setChecked.md create mode 100644 docs/ru/api/wrapper/setSelected.md create mode 100644 docs/ru/api/wrapper/setValue.md create mode 100644 docs/ru/guides/testing-SFCs-with-karma.md diff --git a/docs/ru/README.md b/docs/ru/README.md index 91f9ca68d..5b72e6d26 100644 --- a/docs/ru/README.md +++ b/docs/ru/README.md @@ -11,15 +11,19 @@ * [Чем запускать тесты](guides/choosing-a-test-runner.md) * [Тестирование однофайловых компонентов с Jest](guides/testing-SFCs-with-jest.md) * [Тестирование однофайловых компонентов с Mocha + webpack](guides/testing-SFCs-with-mocha-webpack.md) + * [Testing однофайловых компонентов с Karma](guides/testing-SFCs-with-karma.md) + * [Тестирование асинхронной логики](guides/testing-async-components.md) * [Использование с Vue Router](guides/using-with-vue-router.md) * [Использование с Vuex](guides/using-with-vuex.md) - * [Тестирование асинхронной логики](guides/testing-async-components.md) * [API](api/README.md) * [mount](api/mount.md) - * [shallow](api/shallow.md) + * [shallowMount](api/shallowMount.md) + * [render](api/render.md) + * [renderToString](api/renderToString.md) * [Опции монтирования](api/options.md) - [context](api/options.md#context) - [slots](api/options.md#slots) + - [scopedSlots](api/options.md#scopedslots) - [stubs](api/options.md#stubs) - [mocks](api/options.md#mocks) - [localVue](api/options.md#localvue) @@ -27,6 +31,7 @@ - [attrs](api/options.md#attrs) - [listeners](api/options.md#listeners) - [provide](api/options.md#provide) + - [sync](api/options.md#sync) - [другие опции](api/options.md#other-options) * [Wrapper](api/wrapper/README.md) * [attributes](api/wrapper/attributes.md) @@ -44,28 +49,33 @@ * [isVueInstance](api/wrapper/isVueInstance.md) * [name](api/wrapper/name.md) * [props](api/wrapper/props.md) - * [setComputed](api/wrapper/setComputed.md) + * [setChecked](api/wrapper/setChecked.md) * [setData](api/wrapper/setData.md) * [setMethods](api/wrapper/setMethods.md) * [setProps](api/wrapper/setProps.md) + * [setSelected](api/wrapper/setSelected.md) + * [setValue](api/wrapper/setValue.md) * [text](api/wrapper/text.md) * [trigger](api/wrapper/trigger.md) + * [isVisible](api/wrapper/isVisible.md) * [WrapperArray](api/wrapper-array/README.md) * [at](api/wrapper-array/at.md) * [contains](api/wrapper-array/contains.md) * [exists](api/wrapper/exists.md) * [destroy](api/wrapper-array/destroy.md) + * [filter](api/wrapper-array/filter.md) * [is](api/wrapper-array/is.md) * [isEmpty](api/wrapper-array/isEmpty.md) * [isVueInstance](api/wrapper-array/isVueInstance.md) - * [setComputed](api/wrapper-array/setComputed.md) * [setData](api/wrapper-array/setData.md) * [setMethods](api/wrapper-array/setMethods.md) * [setProps](api/wrapper-array/setProps.md) * [trigger](api/wrapper-array/trigger.md) + * [isVisible](api/wrapper-array/isVisible.md) * [Компоненты](api/components/README.md) * [TransitionStub](api/components/TransitionStub.md) * [TransitionGroupStub](api/components/TransitionGroupStub.md) + * [RouterLinkStub](api/components/RouterLinkStub.md) * [Селекторы](api/selectors.md) * [createLocalVue](api/createLocalVue.md) * [Конфигурация](api/config.md) diff --git a/docs/ru/SUMMARY.md b/docs/ru/SUMMARY.md deleted file mode 100644 index bfc5add55..000000000 --- a/docs/ru/SUMMARY.md +++ /dev/null @@ -1,66 +0,0 @@ -## Содержание - -* [Руководства](guides/README.md) - * [Введение](guides/getting-started.md) - * [Общие советы](guides/common-tips.md) - * [Мышь, клавиши и другие события DOM](guides/dom-events.md) - * [Чем запускать тесты](guides/choosing-a-test-runner.md) - * [Тестирование однофайловых компонентов с Jest](guides/testing-SFCs-with-jest.md) - * [Тестирование однофайловых компонентов с Mocha + webpack](guides/testing-SFCs-with-mocha-webpack.md) - * [Использование с Vue Router](guides/using-with-vue-router.md) - * [Использование с Vuex](guides/using-with-vuex.md) - * [Тестирование асинхронной логики](guides/testing-async-components.md) -* [API](api/README.md) - * [mount](api/mount.md) - * [shallowMount](api/shallowMount.md) - * [Опции монтирования](api/options.md) - - [context](api/options.md#context) - - [slots](api/options.md#slots) - - [stubs](api/options.md#stubs) - - [mocks](api/options.md#mocks) - - [localVue](api/options.md#localvue) - - [attachToDocument](api/options.md#attachtodocument) - - [attrs](api/options.md#attrs) - - [listeners](api/options.md#listeners) - - [provide](api/options.md#provide) - - [другие опции](api/options.md#other-options) - * [Wrapper](api/wrapper/README.md) - * [attributes](api/wrapper/attributes.md) - * [classes](api/wrapper/classes.md) - * [contains](api/wrapper/contains.md) - * [emitted](api/wrapper/emitted.md) - * [emittedByOrder](api/wrapper/emittedByOrder.md) - * [exists](api/wrapper/exists.md) - * [destroy](api/wrapper/destroy.md) - * [find](api/wrapper/find.md) - * [findAll](api/wrapper/findAll.md) - * [html](api/wrapper/html.md) - * [is](api/wrapper/is.md) - * [isEmpty](api/wrapper/isEmpty.md) - * [isVueInstance](api/wrapper/isVueInstance.md) - * [name](api/wrapper/name.md) - * [props](api/wrapper/props.md) - * [setData](api/wrapper/setData.md) - * [setMethods](api/wrapper/setMethods.md) - * [setProps](api/wrapper/setProps.md) - * [text](api/wrapper/text.md) - * [trigger](api/wrapper/trigger.md) - * [WrapperArray](api/wrapper-array/README.md) - * [at](api/wrapper-array/at.md) - * [contains](api/wrapper-array/contains.md) - * [exists](api/wrapper/exists.md) - * [destroy](api/wrapper-array/destroy.md) - * [is](api/wrapper-array/is.md) - * [isEmpty](api/wrapper-array/isEmpty.md) - * [isVueInstance](api/wrapper-array/isVueInstance.md) - * [setComputed](api/wrapper-array/setComputed.md) - * [setData](api/wrapper-array/setData.md) - * [setMethods](api/wrapper-array/setMethods.md) - * [setProps](api/wrapper-array/setProps.md) - * [trigger](api/wrapper-array/trigger.md) - * [Компоненты](api/components/README.md) - * [TransitionStub](api/components/TransitionStub.md) - * [TransitionGroupStub](api/components/TransitionGroupStub.md) - * [Селекторы](api/selectors.md) - * [createLocalVue](api/createLocalVue.md) - * [Конфигурация](api/config.md) diff --git a/docs/ru/api/README.md b/docs/ru/api/README.md index 85e1c030d..42da72b82 100644 --- a/docs/ru/api/README.md +++ b/docs/ru/api/README.md @@ -1,56 +1,9 @@ # API -* [mount](./mount.md) -* [shallow](./shallow.md) -* [Опции монтирования](./options.md) - - [context](./options.md#context) - - [slots](./options.md#slots) - - [stubs](./options.md#stubs) - - [mocks](./options.md#mocks) - - [localVue](./options.md#localvue) - - [attachToDocument](./options.md#attachtodocument) - - [attrs](./options.md#attrs) - - [listeners](./options.md#listeners) - - [provide](./options.md#provide) - - [другие опции](./options.md#other-options) -* [Wrapper](./wrapper/README.md) - * [attributes](./wrapper/attributes.md) - * [classes](./wrapper/classes.md) - * [contains](./wrapper/contains.md) - * [emitted](./wrapper/emitted.md) - * [emittedByOrder](./wrapper/emittedByOrder.md) - * [exists](./wrapper/exists.md) - * [destroy](./wrapper/destroy.md) - * [find](./wrapper/find.md) - * [findAll](./wrapper/findAll.md) - * [html](./wrapper/html.md) - * [is](./wrapper/is.md) - * [isEmpty](./wrapper/isEmpty.md) - * [isVueInstance](./wrapper/isVueInstance.md) - * [name](./wrapper/name.md) - * [props](./wrapper/props.md) - * [setComputed](./wrapper/setComputed.md) - * [setData](./wrapper/setData.md) - * [setMethods](./wrapper/setMethods.md) - * [setProps](./wrapper/setProps.md) - * [text](./wrapper/text.md) - * [trigger](./wrapper/trigger.md) -* [WrapperArray](./wrapper-array/README.md) - * [at](./wrapper-array/at.md) - * [contains](./wrapper-array/contains.md) - * [exists](./wrapper/exists.md) - * [destroy](./wrapper-array/destroy.md) - * [is](./wrapper-array/is.md) - * [isEmpty](./wrapper-array/isEmpty.md) - * [isVueInstance](./wrapper-array/isVueInstance.md) - * [setComputed](./wrapper-array/setComputed.md) - * [setData](./wrapper-array/setData.md) - * [setMethods](./wrapper-array/setMethods.md) - * [setProps](./wrapper-array/setProps.md) - * [trigger](./wrapper-array/trigger.md) -* [Компоненты](./components/README.md) - * [TransitionStub](./components/TransitionStub.md) - * [TransitionGroupStub](./components/TransitionGroupStub.md) -* [Селекторы](./selectors.md) -* [createLocalVue](./createLocalVue.md) -* [Конфигурация](./config.md) +!!!include(docs/ru/api/mount.md)!!! +!!!include(docs/ru/api/shallowMount.md)!!! +!!!include(docs/ru/api/render.md)!!! +!!!include(docs/ru/api/renderToString.md)!!! +!!!include(docs/ru/api/selectors.md)!!! +!!!include(docs/ru/api/createLocalVue.md)!!! +!!!include(docs/ru/api/config.md)!!! \ No newline at end of file diff --git a/docs/ru/api/components/README.md b/docs/ru/api/components/README.md index 517cd1895..b4c577d9d 100644 --- a/docs/ru/api/components/README.md +++ b/docs/ru/api/components/README.md @@ -1,5 +1,7 @@ # Компоненты -vue-test-utils включает утилиты, которые вы можете использовать для создания заглушек компонентов. +Vue Test Utils включает утилиты, которые вы можете использовать для создания заглушек компонентов. -[TransitionStub](./TransitionStub.md) и [TransitionGroupStub](./TransitionGroupStub.md) используются для создания заглушек компонентов `transition` и `transition-group` по умолчанию. Вы можете изменить эти заглушки отредактировав конфигурацию. \ No newline at end of file +!!!include(docs/ru/api/components/RouterLinkStub.md)!!! +!!!include(docs/ru/api/components/TransitionStub.md)!!! +!!!include(docs/ru/api/components/TransitionGroupStub.md)!!! \ No newline at end of file diff --git a/docs/ru/api/components/RouterLinkStub.md b/docs/ru/api/components/RouterLinkStub.md new file mode 100644 index 000000000..143ca670e --- /dev/null +++ b/docs/ru/api/components/RouterLinkStub.md @@ -0,0 +1,20 @@ +## RouterLinkStub + +Компонент для заглушки компонента Vue Router `router-link`. + +Вы можете использовать этот компонент для поиска компонента router-link в дереве рендеринга. + +- **Использование:** + +Чтобы установить его как заглушку в опциях монтирования: + +```js +import { mount, RouterLinkStub } from '@vue/test-utils' + +const wrapper = mount(Component, { + stubs: { + RouterLink: RouterLinkStub + } +}) +expect(wrapper.find(RouterLinkStub).props().to).toBe('/some/path') +``` \ No newline at end of file diff --git a/docs/ru/api/config.md b/docs/ru/api/config.md index bcaec9132..789d875a5 100644 --- a/docs/ru/api/config.md +++ b/docs/ru/api/config.md @@ -1,8 +1,8 @@ # Конфигурация -vue-test-utils включает в себя объект конфигурации для определения опций, используемых vue-test-utils. +Vue Test Utils включает объект конфигурации для определения опций, используемых Vue Test Utils. -## Конфигурация настроек `vue-test-utils` +## Конфигурация настроек Vue Test Utils` ### `stubs` @@ -23,4 +23,74 @@ vue-test-utils включает в себя объект конфигураци import VueTestUtils from '@vue/test-utils' VueTestUtils.config.stubs['my-component'] = '
' +``` + +### `mocks` + +- type: `Object` +- default: `{}` + +По аналогии с `stubs`, значения, переданные в `config.mocks` используются по умолчанию. Любые значения, переданные настройкам монтирования объекта `mocks`, будут иметь приоритет выше, по сравнению с объявленными в `config.mocks`. + +Example: + +```js +import VueTestUtils from '@vue/test-utils' + +VueTestUtils.config.mocks['$store'] = { + state: { + id: 1 + } +} +``` + +### `methods` + +- type: `Object` +- default: `{}` + +Вы можете настроить методы по умолчанию с помощью объекта `config`. Это может быть полезно для плагинов, которые вводят методы в компоненты, такие как [VeeValidate](https://vee-validate.logaretm.com/). Вы можете переопределить методы, установленные в `config`, передав `methods` в настройках монтирования. + +Example: + +```js +import VueTestUtils from '@vue/test-utils' + +VueTestUtils.config.methods['errors'] = () => { + any: () => false +} +``` + +### `provide` + +- type: `Object` +- default: `{}` + +Как `stubs` или `mocks`, значения, переданные `config.provide`, используются по умолчанию. Любые значения, переданные настройкам монтирования объекта `provide`, будут иметь приоритет выше по сравнению с объявленными в `config.provide`. **Обратите внимание, что не поддерживается передача функции в качестве `config.provide`.** + +Пример: + +```js +import VueTestUtils from '@vue/test-utils' + +VueTestUtils.config.provide['$logger'] = { + log: (...args) => { + console.log(...args) + } +} +``` + +### `logModifiedComponents` + +- type: `Boolean` +- default: `true` + +Логирует о предупреждениях, когда для расширенных дочерних компонентов автоматически создаётся заглушка. Скрывает предупреждения, когда установлено значение `false`. В отличие от других опций конфигурации, это невозможно установить в настройках монтирования. + +Пример: + +```js +import VueTestUtils from '@vue/test-utils' + +VueTestUtils.config.logModifiedComponents = false ``` \ No newline at end of file diff --git a/docs/ru/api/mount.md b/docs/ru/api/mount.md index 3717e9324..39ba92502 100644 --- a/docs/ru/api/mount.md +++ b/docs/ru/api/mount.md @@ -127,4 +127,4 @@ describe('Foo', () => { }) ``` -- **См. также:** [Wrapper](wrapper/README.md) +- **См. также:** [Wrapper](wrapper/) diff --git a/docs/ru/api/options.md b/docs/ru/api/options.md index 6895016f3..6a4ffb297 100644 --- a/docs/ru/api/options.md +++ b/docs/ru/api/options.md @@ -1,11 +1,10 @@ # Опции монтирования -Опции для `mount` и `shallow`. Объект опций может содержать как настройки монтирования `vue-test-utils`, так и сырые опции Vue. - -## Специальные опции монтирования `vue-test-utils` +Опции для `mount` и `shallowMount`. Объект опций может содержать как настройки монтирования Vue Test Utils, так и другие опции Vue. - [`context`](#context) - [`slots`](#slots) +- [`scopedSlots`](#scopedslots) - [`stubs`](#stubs) - [`mocks`](#mocks) - [`localVue`](#localvue) @@ -13,6 +12,7 @@ - [`attrs`](#attrs) - [`listeners`](#listeners) - [`provide`](#provide) +- [`sync`](#sync) ### `context` @@ -48,7 +48,7 @@ expect(wrapper.is(Component)).toBe(true) import Foo from './Foo.vue' import Bar from './Bar.vue' -const wrapper = shallow(Component, { +const wrapper = shallowMount(Component, { slots: { default: [Foo, Bar], fooBar: Foo, // будет соответствовать `` @@ -59,11 +59,37 @@ const wrapper = shallow(Component, { expect(wrapper.find('div')).toBe(true) ``` +## scopedSlots + +- type: `{ [name: string]: string }` + +Предоставляет объект содержимое слотов с ограниченной областью видимости для компонента. Ключ соответствует имени слота. Значение может быть строкой шаблона. + +Есть три ограничения. + +* Эта опция поддерживается только с vue@2.5+. + +* Вы не можете использовать тег `