diff --git a/README.md b/README.md index eedbb618d..6ce145f24 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ Component testing utils for Vue 3. +## Languages + +[🇫🇷 French version of this README.md](https://github.com/vuejs/test-utils/tree/main/docs/fr/README.md) + ## Installation and Usage - yarn: `yarn add @vue/test-utils --dev` @@ -31,47 +35,47 @@ This is table for those coming from VTU 1, comparing the two APIs. Some things a ### Mounting Options -| option | status | notes | -| ---------------- | ------ | ----------------------------------------------------------------------------------- | -| data | ✅ | -| slots | ✅ | -| mocks | ✅ | nested in `global` | -| propsData | ✅ | now called `props` | -| provide | ✅ | nested in `global` | -| mixins | ✅ | (new!) nested in `global` | -| plugins | ✅ | (new!) nested in `global` | -| component | ✅ | (new!) nested in `global` | -| directives | ✅ | (new!) nested in `global` | -| stubs | ✅ | -| attachToDocument | ✅ | renamed `attachTo`. See [here](https://github.com/vuejs/vue-test-utils/pull/1492) | -| attrs | ✅ | -| scopedSlots | ⚰️ | scopedSlots are merged with `slots` in Vue 3 | -| context | ⚰️ | different from Vue 2, does not make sense anymore. | -| localVue | ⚰️ | no longer required - Vue 3 there is no global Vue instance to mutate. | -| listeners | ⚰️ | no longer exists in Vue 3 | +| option | status | notes | +|------------------|--------|-----------------------------------------------------------------------------------| +| data | ✅ | +| slots | ✅ | +| mocks | ✅ | nested in `global` | +| propsData | ✅ | now called `props` | +| provide | ✅ | nested in `global` | +| mixins | ✅ | (new!) nested in `global` | +| plugins | ✅ | (new!) nested in `global` | +| component | ✅ | (new!) nested in `global` | +| directives | ✅ | (new!) nested in `global` | +| stubs | ✅ | +| attachToDocument | ✅ | renamed `attachTo`. See [here](https://github.com/vuejs/vue-test-utils/pull/1492) | +| attrs | ✅ | +| scopedSlots | ⚰️ | scopedSlots are merged with `slots` in Vue 3 | +| context | ⚰️ | different from Vue 2, does not make sense anymore. | +| localVue | ⚰️ | no longer required - Vue 3 there is no global Vue instance to mutate. | +| listeners | ⚰️ | no longer exists in Vue 3 | | parentComponent | ⚰️ | ### Wrapper API (mount) | method | status | notes | -| -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------- | -| attributes | ✅ | -| classes | ✅ | -| exists | ✅ | -| find | ✅ | only `querySelector` syntax is supported. `find(Comp)` under discussion [here](https://github.com/vuejs/vue-test-utils/issues/1498) | -| emitted | ✅ | -| findAll | ✅ | see above. `.vm` is different to Vue 2. We are exploring options. | -| get | ✅ | -| html | ✅ | -| setValue | ✅ | works for select, checkbox, radio button, input, textarea. Returns `nextTick`. | -| text | ✅ | -| trigger | ✅ | returns `nextTick`. You can do `await wrapper.find('button').trigger('click')` | -| setProps | ✅ | -| props | ✅ | -| setData | ✅ | -| destroy | ✅ | renamed to `unmount` to match Vue 3 lifecycle hook name. | -| props | ✅ | -| isVisible | ✅ | +|----------------|--------|-------------------------------------------------------------------------------------------------------------------------------------| +| attributes | ✅ | +| classes | ✅ | +| exists | ✅ | +| find | ✅ | only `querySelector` syntax is supported. `find(Comp)` under discussion [here](https://github.com/vuejs/vue-test-utils/issues/1498) | +| emitted | ✅ | +| findAll | ✅ | see above. `.vm` is different to Vue 2. We are exploring options. | +| get | ✅ | +| html | ✅ | +| setValue | ✅ | works for select, checkbox, radio button, input, textarea. Returns `nextTick`. | +| text | ✅ | +| trigger | ✅ | returns `nextTick`. You can do `await wrapper.find('button').trigger('click')` | +| setProps | ✅ | +| props | ✅ | +| setData | ✅ | +| destroy | ✅ | renamed to `unmount` to match Vue 3 lifecycle hook name. | +| props | ✅ | +| isVisible | ✅ | | contains | ⚰️ | use `find` | | emittedByOrder | ⚰️ | use `emitted` | | setSelected | ⚰️ | now part of `setValue` | diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 02054a7ee..3f77b27a0 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -1,17 +1,122 @@ -import { defineConfig } from 'vitepress' -import packageJSON from '../../package.json' +import { defineConfig } from 'vitepress'; +import { frLocaleConfig } from "../fr/.vitepress/locale-config"; export default defineConfig({ title: `Vue Test Utils`, description: 'The documentation for the official Vue Test Utils', locales: { - '/': { + "/": { + label: "English", lang: 'en-US', title: `Vue Test Utils` - } + }, + "/fr/": { + label: "Français", + title: "Vue Test Utils", + lang: "fr-FR", + description: "La documentation officielle de Vue Test Utils", + }, }, head: [['link', { rel: 'icon', href: `/logo.png` }]], themeConfig: { + locales: { + "/": { + label: 'English', + selectText: 'Languages', + nav: [ + { text: 'Guide', link: '/guide/' }, + { text: 'API Reference', link: '/api/' }, + { text: 'Migrating from Vue 2', link: '/migration/' }, + { + text: 'Changelog', + link: 'https://github.com/vuejs/test-utils/releases' + } + ], + sidebar: [ + { + text: 'Installation', + link: '/installation/' + }, + { + text: 'Essentials', + collapsable: false, + children: [ + { text: 'Getting Started', link: '/guide/' }, + { text: 'A Crash Course', link: '/guide/essentials/a-crash-course' }, + { + text: 'Conditional Rendering', + link: '/guide/essentials/conditional-rendering' + }, + { + text: 'Testing Emitted Events', + link: '/guide/essentials/event-handling' + }, + { text: 'Testing Forms', link: '/guide/essentials/forms' }, + { + text: 'Passing Data to Components', + link: '/guide/essentials/passing-data' + }, + { + text: 'Write components that are easy to test', + link: '/guide/essentials/easy-to-test' + } + ] + }, + { + text: 'Vue Test Utils in depth', + collapsable: false, + children: [ + { text: 'Slots', link: '/guide/advanced/slots' }, + { + text: 'Asynchronous Behavior', + link: '/guide/advanced/async-suspense' + }, + { + text: 'Making HTTP Requests', + link: '/guide/advanced/http-requests' + }, + { text: 'Transitions', link: '/guide/advanced/transitions' }, + { + text: 'Component Instance', + link: '/guide/advanced/component-instance' + }, + { + text: 'Reusability and Composition', + link: '/guide/advanced/reusability-composition' + }, + { text: 'Testing v-model', link: '/guide/advanced/v-model' }, + { text: 'Testing Vuex', link: '/guide/advanced/vuex' }, + { text: 'Testing Vue Router', link: '/guide/advanced/vue-router' }, + { text: 'Testing Teleport', link: '/guide/advanced/teleport' }, + { + text: 'Stubs and Shallow Mount', + link: '/guide/advanced/stubs-shallow-mount' + } + ] + }, + { + text: 'Extending Vue Test Utils', + collapsable: false, + children: [ + { text: 'Plugins', link: '/guide/extending-vtu/plugins' }, + { + text: 'Community and Learning', + link: '/guide/extending-vtu/community-learning' + } + ] + }, + { + text: 'Migrating from Vue 2', + link: '/migration/' + }, + { + text: 'API Reference', + link: '/api/' + } + ] + }, + "/fr/": frLocaleConfig, + }, repo: 'vuejs/test-utils', docsRepo: 'vuejs/test-utils', docsDir: 'docs', diff --git a/docs/api/index.md b/docs/api/index.md index 6bb67bfa5..47d5b7c33 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -44,7 +44,7 @@ test('mounts a component', () => { Notice that `mount` accepts a second parameter to define the component's state configuration. -**Example: mounting with component props and a Vue App plugin** +**Exemple : mounting with component props and a Vue App plugin** ```js const wrapper = mount(Component, { @@ -1947,7 +1947,7 @@ type GlobalMountOptions = { Instead of configuring mounting options on a per test basis, you can configure them for your entire test suite. These will be used by default every time you `mount` a component. If desired, you can then override your defaults on a per test basis. -**Example:** +**Exemple :** An example might be globally mocking the `$t` variable from vue-i18n and a component: diff --git a/docs/fr/.vitepress/locale-config.ts b/docs/fr/.vitepress/locale-config.ts new file mode 100644 index 000000000..fbecd52eb --- /dev/null +++ b/docs/fr/.vitepress/locale-config.ts @@ -0,0 +1,100 @@ +import { DefaultTheme } from "vitepress"; + +const frLocaleConfig: DefaultTheme.LocaleConfig & Omit = { + label: 'Français', + selectText: 'Langues', + nav: [ + { text: 'Guide', link: '/fr/guide/' }, + { text: 'API', link: '/fr/api/' }, + { text: 'Migrer depuis Vue 2', link: '/fr/migration/' }, + { + text: 'Journal de modifications', + link: 'https://github.com/vuejs/test-utils/releases' + } + ], + sidebar: [ + { + text: 'Installation', + link: '/fr/installation/' + }, + { + text: 'Les Bases', + collapsable: false, + children: [ + { text: 'Pour commencer', link: '/fr/guide/' }, + { text: 'Cours rapide', link: '/fr/guide/essentials/a-crash-course' }, + { + text: 'Rendu conditionnel', + link: '/fr/guide/essentials/conditional-rendering' + }, + { + text: 'Tester les évènements émis', + link: '/fr/guide/essentials/event-handling' + }, + { text: 'Tester les formulaires', link: '/fr/guide/essentials/forms' }, + { + text: 'Passer des données aux Composants', + link: '/fr/guide/essentials/passing-data' + }, + { + text: 'Écrire des composants facile à tester', + link: '/fr/guide/essentials/easy-to-test' + } + ] + }, + { + text: 'Vue Test Utils en détail', + collapsable: false, + children: [ + { text: 'Slots', link: '/fr/guide/advanced/slots' }, + { + text: 'Comportement asynchrone', + link: '/fr/guide/advanced/async-suspense' + }, + { + text: 'Faire des requêtes HTTP', + link: '/fr/guide/advanced/http-requests' + }, + { text: 'Transitions', link: '/fr/guide/advanced/transitions' }, + { + text: 'Instance de Composant', + link: '/fr/guide/advanced/component-instance' + }, + { + text: 'Réutilisabilité et Composition', + link: '/fr/guide/advanced/reusability-composition' + }, + { text: 'Tester v-model', link: '/fr/guide/advanced/v-model' }, + { text: 'Tester Vuex', link: '/fr/guide/advanced/vuex' }, + { text: 'Tester Vue Router', link: '/fr/guide/advanced/vue-router' }, + { text: 'Tester Teleport', link: '/fr/guide/advanced/teleport' }, + { + text: 'Composants de Substitution (Stubs) et Montage Partiel', + link: '/fr/guide/advanced/stubs-shallow-mount' + }, + { text: 'Tester le Rendu côté Serveur (SSR)', link: '/fr/guide/advanced/ssr' } + ] + }, + { + text: 'Extensions de Vue Test Utils', + collapsable: false, + children: [ + { text: 'Plugins', link: '/fr/guide/extending-vtu/plugins' }, + { + text: 'Communauté et Apprentissage', + link: '/fr/guide/extending-vtu/community-learning' + } + ] + }, + { + text: 'Migrer depuis Vue 2', + link: '/fr/migration/' + }, + { + text: 'API', + link: '/fr/api/' + } + ] +}; + +export { frLocaleConfig }; diff --git a/docs/fr/README.md b/docs/fr/README.md new file mode 100644 index 000000000..3372687fc --- /dev/null +++ b/docs/fr/README.md @@ -0,0 +1,83 @@ +# Vue Test Utils + +Utilitaire de Test de Composants pour Vue 3. + +## Installation et Utilisation + +- yarn: `yarn add @vue/test-utils --dev` +- npm: `npm install @vue/test-utils --save-dev` + +Lancez-vous avec la [documentation](https://test-utils.vuejs.org/fr). + +## Vous venez de Vue 2 + Test Utils v1? + +[Jetez un œil au guide de migration](https://test-utils.vuejs.org/migration/fr). C'est encore en cours de développement. Si vous rencontrez un problème ou quelque chose qui ne fonctionne plus alors qu'il fonctionnait auparavant dans Vue Test Utils v1, veuillez ouvrir une question sur GitHub. + +## Documentation + +Voir la [documentation](https://test-utils.vuejs.org/fr). + +## Développement + +Commencez en exécutant la commande `pnpm install`. Vous pouvez exécuter les tests avec la commande `pnpm test`. C'est tout ! + +## Comparaison avec Vue Test Utils v1 (qui cible Vue 2) + +Voici un tableau pour ceux qui viennent de VTU 1, comparant les deux API. Certaines choses sont encore en cours de développement. + +- ✅ - implémenté +- ❌ - pas encore implémenté +- ⚰️ - ne sera pas implémenté (si vous trouvez un scénario qui prouve son utilité, veuillez ouvrir une question sur GitHub) + +### Mounting Options + +| option | status | notes | +|------------------|--------|---------------------------------------------------------------------------------------| +| data | ✅ | +| slots | ✅ | +| mocks | ✅ | situé dans `global` | +| propsData | ✅ | s'appelle maintenant `props` | +| provide | ✅ | situé dans `global` | +| mixins | ✅ | (nouveau !) situé dans `global` | +| plugins | ✅ | (nouveau !) situé dans `global` | +| component | ✅ | (nouveau !) situé dans `global` | +| directives | ✅ | (nouveau !) situé dans `global` | +| stubs | ✅ | +| attachToDocument | ✅ | renommé en `attachTo`. Voir [here](https://github.com/vuejs/vue-test-utils/pull/1492) | +| attrs | ✅ | +| scopedSlots | ⚰️ | `scopedSlots` sont fusionnés dans `slots` dans Vue 3 | +| context | ⚰️ | différent depuis Vue 2, n'a plus d'utilité. | +| localVue | ⚰️ | n'est plus obligatoire - Vue 3 il n'y a plus d'instance globale à muter. | +| listeners | ⚰️ | n'existe plus dans Vue 3 | +| parentComponent | ⚰️ | + +### Wrapper API (mount) + +| method | status | notes | +|----------------|--------|-------------------------------------------------------------------------------------------------------------------------------------| +| attributes | ✅ | +| classes | ✅ | +| exists | ✅ | +| find | ✅ | seulement la syntaxe `querySelector` est supportée. `find(Comp)` discuté [ici](https://github.com/vuejs/vue-test-utils/issues/1498) | +| emitted | ✅ | +| findAll | ✅ | voir ci-dessus. `.vm` est différent de celui de Vue 2. Nous étudions les options. | +| get | ✅ | +| html | ✅ | +| setValue | ✅ | fonctionne avec les `select`, `checkbox`, `radio button`, `input`, `textarea`. Retourne `nextTick`. | +| text | ✅ | +| trigger | ✅ | retourne `nextTick`. Vous pouvez écrire `await wrapper.find('button').trigger('click')` | +| setProps | ✅ | +| props | ✅ | +| setData | ✅ | +| destroy | ✅ | renommé en `unmount` pour correspondre au cycle de vie Vue 3. | +| props | ✅ | +| isVisible | ✅ | +| contains | ⚰️ | utilisez `find` | +| emittedByOrder | ⚰️ | utilisez `emitted` | +| setSelected | ⚰️ | fait maintenant parti de `setValue` | +| setChecked | ⚰️ | fait maintenant parti de `setValue` | +| is | ⚰️ | +| isEmpty | ⚰️ | utilisez une fonction comme [celle-ci](https://github.com/testing-library/jest-dom#tobeempty) | +| isVueInstance | ⚰️ | +| name | ⚰️ | +| setMethods | ⚰️ | diff --git a/docs/fr/api/index.md b/docs/fr/api/index.md new file mode 100644 index 000000000..eafb8e41e --- /dev/null +++ b/docs/fr/api/index.md @@ -0,0 +1,2028 @@ +--- +sidebar: auto +--- + +# API + +## mount + +Crée un `Wrapper` qui contient le composant Vue monté et rendu pour le test. + +**Signature :** + +```ts +interface MountingOptions { + attachTo?: HTMLElement | string + attrs?: Record + data?: () => {} extends Data ? any : Data extends object ? Partial : any + props?: (RawProps & Props) | ({} extends Props ? null : never) + slots?: { [key: string]: Slot } & { default?: Slot } + global?: GlobalMountOptions + shallow?: boolean +}; + +function mount(Component, options?: MountingOptions): VueWrapper +``` + +**Utilisation :** + +`mount` est la méthode principale exposée par Vue Test Utils. Elle crée une application Vue 3 qui contient et rend le composant en cours de test. En retour, il crée un wrapper pour agir et vérifier le comportement du composant. + +```js +import { mount } from '@vue/test-utils'; + +const Component = { + template: '
Bonjour tout le monde
', +}; + +test('monte un composant', () => { + const wrapper = mount(Component, {}); + + expect(wrapper.html()).toContain('Bonjour tout le monde'); +}); +``` + +Remarquez que `mount` accepte un second paramètre pour définir l'état du composant. + +**Exemple : monter un composant avec des `props` et un plugin Vue** + +```js +const wrapper = mount(Component, { + props: { + msg: 'Bonjour tout le monde', + }, + global: { + plugins: [vuex], + }, +}); +``` + +#### options.global + +Parmi les états du composant, vous pouvez configurer l'application Vue 3 par la propriété de configuration [`MountingOptions.global` config property](#global). Cela peut être utile pour fournir des valeurs simulées dont vos composants pourraient avoir besoin. + +::: tip +Si vous vous retrouvez à définir une configuration commune de l'application pour de nombreux tests, vous pouvez définir la configuration pour tous vos tests complet à l'aide de l'[objet `config`](#config) exporté. +::: + +### attachTo + +Spécifie le nœud où monter le composant. + +**Signature :** + +```ts +attachTo?: HTMLElement | string +``` + +**Utilisation :** + +Peut être un sélecteur CSS valide ou un [`Element`](https://developer.mozilla.org/fr-FR/docs/Web/API/Element) connecté au document. + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +document.body.innerHTML = ` +
+

Pas une app Vue

+
+
+`; + +test('monte sur un composant spécifique', () => { + const wrapper = mount(Component, { + attachTo: document.getElementById('app'), + }); + + expect(document.body.innerHTML).toBe(` +
+

Pas une app Vue

+

Composant Vue

+
+ `); +}); +``` + +### attrs + +Définie les attributs HTML d'un composant. + +**Signature :** + +```ts +attrs?: Record +``` + +**Utilisation :** + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('attrs', () => { + const wrapper = mount(Component, { + attrs: { + id: 'Bonjour', + disabled: true, + }, + }); + + expect(wrapper.attributes()).toEqual({ + disabled: 'true', + id: 'Bonjour', + }); +}); +``` + +Remarquez que définir une propriété remplacera toujours l'attribut : + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('l\'attribut est remplacé par la prop éponyme', () => { + const wrapper = mount(Component, { + props: { + message: 'Bonjour tout le monde', + }, + attrs: { + message: 'cette valeur va être remplacée', + }, + }); + + expect(wrapper.props()).toEqual({ message: 'Bonjour tout le monde' }); + expect(wrapper.attributes()).toEqual({}); +}); +``` + +### data + +Remplace la `data` par défaut d'un composant. Doit être une fonction. + +**Signature :** + +```ts +data?: () => {} extends Data ? any : Data extends object ? Partial : any +``` + +**Utilisation :** + +`Component.vue` + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('data', () => { + const wrapper = mount(Component, { + data() { + return { + message: 'vous' + }; + }, + }); + + expect(wrapper.html()).toContain('Bonjour vous'); +}); +``` + +### props + +Définie les `props` d'un composant lorsqu'il est monté. + +**Signature :** + +```ts +props?: (RawProps & Props) | ({} extends Props ? null : never) +``` + +**Utilisation :** + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('props', () => { + const wrapper = mount(Component, { + props: { + count: 5, + }, + }); + + expect(wrapper.html()).toContain('Compteur: 5'); +}); +``` + +### slots + +Définie les valeurs des slots sur un composant. + +**Signature :** + +```ts +type Slot = VNode | string | { render: Function } | Function | Component + +slots?: { [key: string]: Slot } & { default?: Slot } +``` + +**Utilisation :** + +Les `slots` peuvent être une `string` ou toute définition de composant valide importée d'un fichier `.vue` ou directement fournie. + +`Component.vue`: + +```vue + +``` + +`Bar.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { h } from 'vue'; +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; +import Bar from './Bar.vue'; + +test('affiche le contenu du slot', () => { + const wrapper = mount(Component, { + slots: { + default: 'Défaut', + first: h('h1', {}, 'Slot Nommé'), + second: Bar, + }, + }); + + expect(wrapper.html()).toBe('

Slot Nommé

Défaut
Bar
'); +}); +``` + +### global + +**Signature :** + +```ts +type GlobalMountOptions = { + plugins?: (Plugin | [Plugin, ...any[]])[] + config?: Partial> + mixins?: ComponentOptions[] + mocks?: Record + provide?: Record + components?: Record + directives?: Record + stubs?: Stubs = Record | Array + renderStubDefaultSlot?: boolean +}; +``` + +Vous pouvez configurer toutes les options `global` à la fois pour chaque test, mais aussi pour l'ensemble des tests. [Voir comment configurer les valeurs par défaut à l'échelle du projet](#config-global). + +#### global.components + +Enregistre les composants de manière globale pour le composant monté. + +**Signature :** + +```ts +components?: Record +``` + +**Utilisation :** + +`Component.vue`: + +```vue + + + +``` + +`GlobalComponent.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import GlobalComponent from '@/components/GlobalComponent'; +import Component from './Component.vue'; + +test('global.components', () => { + const wrapper = mount(Component, { + global: { + components: { + GlobalComponent, + }, + }, + }); + + expect(wrapper.find('.global-component').exists()).toBe(true); +}); +``` + +#### global.config + +Configure [la configuration globale de l'application Vue](https://v3.vuejs.org/api/application-config.html#application-config). + +**Signature :** + +```ts +config?: Partial> +``` + +#### global.directives + +Enregistre une [directive](https://v3.vuejs.org/api/directives.html#directives) de manière globale pour le composant monté. + +**Signature :** + +```ts +directives?: Record +``` + +**Utilisation :** + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; + +import Directive from '@/directives/Directive'; + +const Component = { + template: '
Foo
', +}; + +test('global.directives', () => { + const wrapper = mount(Component, { + global: { + directives: { + Bar: Directive // Bar correspond à v-bar + }, + }, + }); +}); +``` + +#### global.mixins + +Enregistre un [mixin](https://v3.vuejs.org/guide/mixins.html) de manière globale pour le composant monté. + +**Signature :** + +```ts +mixins?: ComponentOptions[] +``` + +**Utilisation :** + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('global.mixins', () => { + const wrapper = mount(Component, { + global: { + mixins: [mixin], + }, + }); +}); +``` + +#### global.mocks + +Simule une propriété d'instance globale. Peut être utilisé pour simuler `this.$store`, `this.$router`, etc. + +**Signature :** + +```ts +mocks?: Record +``` + +**Utilisation :** + +::: warning +Ceci est conçu pour simuler des variables injectées par des plugins tiers, pas les propriétés natives de Vue telles que `$root`, `$children`, etc. +::: + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('global.mocks', async () => { + const $store = { + dispatch: jest.fn(), + }; + + const wrapper = mount(Component, { + global: { + mocks: { + $store, + }, + }, + }); + + await wrapper.find('button').trigger('click'); + + expect($store.dispatch).toHaveBeenCalledWith('click'); +}); +``` + +#### global.plugins + +Installe des plugins sur le composant monté. + +**Signature :** + +```ts +plugins?: (Plugin | [Plugin, ...any[]])[] +``` + +**Utilisation :** + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +import myPlugin from '@/plugins/myPlugin'; + +test('global.plugins', () => { + mount(Component, { + global: { + plugins: [myPlugin], + }, + }); +}); +``` + +Pour utiliser des plugins avec des options, un tableau d'options peut être passé. + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('global.plugins avec options', () => { + mount(Component, { + global: { + plugins: [Plugin, [PluginWithOptions, 'argument 1', 'un autre argument']], + }, + }); +}); +``` + +#### global.provide + +Fournit des données utilisables dans la fonction `setup` via `inject`. + +**Signature :** + +```ts +provide?: Record +``` + +**Utilisation :** + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('global.provide', () => { + const wrapper = mount(Component, { + global: { + provide: { + Theme: 'sombre', + }, + }, + }); + + console.log(wrapper.html()); //=>
Le thème est sombre
+}); +``` + +Si vous utilisez un `Symbol` ES6 pour votre clé, vous pouvez l'utiliser dynamiquement : + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +const ThemeSymbol = Symbol(); + +mount(Component, { + global: { + provide: { + [ThemeSymbol]: 'value', + }, + }, +}); +``` + +#### global.renderStubDefaultSlot + +Affiche le contenu du `slot default`, même en utilisant `shallow` ou `shallowMount`. + +**Signature :** + +```ts +renderStubDefaultSlot?: boolean +``` + +**Utilisation :** + +**false** par défaut. + +`Component.vue` + +```vue + + + +``` + +`AnotherComponent.vue` + +```vue + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('global.renderStubDefaultSlot', () => { + const wrapper = mount(ComponentWithSlots, { + slots: { + default: '
Mon contenu
', + }, + shallow: true, + global: { + renderStubDefaultSlot: true, + }, + }); + + expect(wrapper.html()).toBe( + '
Mon contenu
' + ); +}); +``` + +En raison de limitations techniques, **ce comportement ne peut pas être étendu aux slots autres que ceux par défaut**. + +#### global.stubs + +Définit un composant de remplacement (`stub`) global sur le composant monté. + +**Signature :** + +```ts +stubs?: Record +``` + +**Utilisation :** + +Substitue `Transition` et `TransitionGroup` par défaut. + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('global.stubs en utilisant la syntaxe en tableau', () => { + const wrapper = mount(Component, { + global: { + stubs: ['Foo'], + }, + }); + + expect(wrapper.html()).toEqual('
'); +}); + +test('global.stubs en utilisant la syntaxe en objet', () => { + const wrapper = mount(Component, { + global: { + stubs: { Foo: true }, + }, + }); + + expect(wrapper.html()).toEqual('
'); +}); + +test('global.stubs en utilisant un composant personnalisé', () => { + const CustomStub = { + name: 'CustomStub', + template: '

Contenu personnalisé du composant de substitution

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

Contenu personnalisé du composant de substitution

'); +}); +``` + +### shallow + +Substitue tous les composants enfants du composant. + +**Signature :** + +```ts +shallow?: boolean +``` + +**Utilisation :** + +**false** par défaut. + +`Component.vue` + +```vue + + + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('shallow', () => { + const wrapper = mount(Component, { shallow: true }); + + expect(wrapper.html()).toEqual( + ``, + ); +}); +``` + +::: tip +Utiliser `shallowMount()` revient à monter un composant avec l'option `shallow: true`. +::: + +## Méthodes de Wrapper + +Lorsque vous utilisez `mount`, un `VueWrapper` est retourné avec un certain nombre de méthodes utiles pour les tests. Un `VueWrapper` est une enveloppe autour de votre instance de composant. + +Notez que des méthodes telles que `find` retournent un `DOMWrapper`, qui est une enveloppe autour des nœuds DOM dans votre composant et ses enfants. Les deux implémentent une API similaire. + +### attributes + +Retourne les attributs d'un nœud du DOM. + +**Signature :** + +```ts +attributes(): { [key: string]: string } +attributes(key: string): string +attributes(key?: string): { [key: string]: string } | string +``` + +**Utilisation :** + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('attributs', () => { + const wrapper = mount(Component); + + expect(wrapper.attributes('id')).toBe('foo'); + expect(wrapper.attributes('class')).toBe('bar'); +}); +``` + +### classes + +**Signature :** + +```ts +classes(): string[] +classes(className: string): boolean +classes(className?: string): string[] | boolean +``` + +**Utilisation :** + +Retourne les classes d'un élément sous la forme d'un tableau. + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('classes', () => { + const wrapper = mount(Component) + + expect(wrapper.classes()).toContain('my-span'); + expect(wrapper.classes('my-span')).toBe(true); + expect(wrapper.classes('not-existing')).toBe(false); +}); +``` + +### emitted + +Retourne tous les évènements émis par un Composant. + +**Signature :** + +```ts +emitted(): Record +emitted(eventName: string): undefined | T[] +emitted(eventName?: string): undefined | T[] | Record +``` + +**Utilisation :** + +Les arguments sont stockés dans un tableau, de sorte que vous pouvez vérifier les arguments qui ont été émis avec chaque événement. + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('emitted', () => { + const wrapper = mount(Component) + + // wrapper.emitted() sera égal à { politesse: [ ['bonjour'], ['au revoir'] ] } + + expect(wrapper.emitted()).toHaveProperty('politesse'); + expect(wrapper.emitted().greet).toHaveLength(2); + expect(wrapper.emitted().greet[0]).toEqual(['bonjour']); + expect(wrapper.emitted().greet[1]).toEqual(['au revoir']); +}); +``` + +### exists + +Vérifie si un élément existe ou non. + +**Signature :** + +```ts +exists(): boolean +``` + +**Utilisation :** + +Nous pouvons utiliser la même syntaxe que `querySelector` implémente. + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('existe', () => { + const wrapper = mount(Component); + + expect(wrapper.find('span').exists()).toBe(true); + expect(wrapper.find('p').exists()).toBe(false); +}); +``` + +### find + +Cherche un élément et retourne un `DOMWrapper` si un élément est trouvé. + +**Signature :** + +```ts +find(selector: K): DOMWrapper +find(selector: K): DOMWrapper +find(selector: string): DOMWrapper +find(selector: string): DOMWrapper +find(selector: string | RefSelector): DOMWrapper; +``` + +**Utilisation :** + +Vous pouvez utiliser la même syntaxe qu'implémente `querySelector`. `find` est en quelque sorte un alias pour `querySelector`. En plus, vous pouvez rechercher des références d'éléments. + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('cherche', () => { + const wrapper = mount(Component); + + wrapper.find('span') //=> trouvé; retourne DOMWrapper + wrapper.find('[data-test="span"]') //=> trouvé; retourne DOMWrapper + wrapper.find({ ref: 'span' }); //=> trouvé; retourne DOMWrapper + wrapper.find('p') //=> rien de trouvé; retourne ErrorWrapper +}); +``` + +### findAll + +Similaire à `find`, mais retourne un tableau de `DOMWrapper`. + +**Signature :** + +```ts +findAll(selector: K): DOMWrapper[] +findAll(selector: K): DOMWrapper[] +findAll(selector: string): DOMWrapper[] +findAll(selector: string): DOMWrapper[] +``` + +**Utilisation :** + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import BaseTable from './BaseTable.vue'; + +test('trouve plusieurs éléments', () => { + const wrapper = mount(BaseTable); + + // .findAll() retourne un tableau de DOMWrappers + const thirdRow = wrapper.findAll('span')[2]; +}); +``` + +### findComponent + +Trouve une instance de composant Vue et renvoie un `VueWrapper` si trouvé. Renvoie un `ErrorWrapper` sinon. + +**Signature :** + +```ts +findComponent(selector: string): WrapperLike +findComponent(selector: T | Exclude): VueWrapper> +findComponent(selector: T | string): DOMWrapper +findComponent(selector: NameSelector | RefSelector): VueWrapper +findComponent(selector: T | FindComponentSelector): VueWrapper +findComponent(selector: FindComponentSelector): WrapperLike +``` + +**Utilisation :** + +`findComponent` supporte plusieurs syntaxes : + +| Syntaxe | Exemple | Détails | +|------------------|-------------------------------|----------------------------------------------------------| +| querySelector | `findComponent('.component')` | Trouve comme à un sélecteur CSS standard. | +| Nom du Composant | `findComponent({name: 'a'})` | Trouve en PascalCase, snake-case et camelCase. | +| Ref du Composant | `findComponent({ref: 'ref'})` | Trouve la reference directe d'un composant enfant monté. | +| SFC | `findComponent(Component)` | Trouve directement un composant importé. | + +`Foo.vue` + +```vue + + + +``` + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +import Foo from '@/Foo.vue'; + +test('trouve le composant', () => { + const wrapper = mount(Component); + + // Toutes les requêtes suivantes retourneront un `VueWrapper` + + wrapper.findComponent('.foo'); + wrapper.findComponent('[data-test="foo"]'); + + wrapper.findComponent({ name: 'Foo' }); + + wrapper.findComponent({ ref: 'foo' }); + + wrapper.findComponent(Foo); +}); +``` + +:::warning +Si `ref` dans le composant pointe vers un élément HTML, `findComponent` renverra un conteneur vide. C'est le comportement attendu. +::: + +:::warning Utilisation avec des sélecteurs CSS +L'utilisation de `findComponent` avec un sélecteur CSS peut avoir un comportement innatendu. + +Voici un exemple : + +```js +const ChildComponent = { + name: 'Child', + template: '
', +}; +const RootComponent = { + name: 'Root', + components: { ChildComponent }, + template: '', +}; +const wrapper = mount(RootComponent); +const rootByCss = wrapper.findComponent('.root'); // => trouve Root +expect(rootByCss.vm.$options.name).toBe('Root'); +const childByCss = wrapper.findComponent('.child'); +expect(childByCss.vm.$options.name).toBe('Root'); // => toujours Root +``` + +La raison de ce comportement est que `RootComponent` et `ChildComponent` partagent le même nœud DOM et que seul le premier composant correspondant est inclus pour chaque nœud DOM unique. +::: + +:::info Type WrapperLike en utilisant un sélecteur CSS +Lors de l'utilisation de `wrapper.findComponent('.foo')` par exemple, VTU renverra le type `WrapperLike`. Cela est dû au fait que les composants fonctionnels auraient besoin d'un `DOMWrapper` au lieu d'un `VueWrapper`. Vous pouvez forcer le retour d'un `VueWrapper` en fournissant le type de composant correct : + +```typescript +wrapper.findComponent('.foo'); // retourne WrapperLike +wrapper.findComponent('.foo'); // retourne VueWrapper +wrapper.findComponent('.foo'); // retourne VueWrapper +``` +::: + +### findAllComponents + +**Signature :** + +```ts +findAllComponents(selector: string): WrapperLike[] +findAllComponents(selector: T | Exclude): VueWrapper>[] +findAllComponents(selector: string): DOMWrapper[] +findAllComponents(selector: T): DOMWrapper[] +findAllComponents(selector: NameSelector): VueWrapper[] +findAllComponents(selector: T | FindAllComponentsSelector): VueWrapper[] +findAllComponents(selector: FindAllComponentsSelector): WrapperLike[] +``` + +**Utilisation :** + +Similaire à `findComponent` mais trouve toutes les instances de composant Vue qui correspondent à la requête. Renvoie un tableau de `VueWrapper`. + +:::warning +La syntaxe `ref` n'est pas prise en charge dans findAllComponents. Toutes les autres syntaxes de requête sont valides. +::: + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('trouve tous les composants', () => { + const wrapper = mount(Component); + + // Retourne un tableau de VueWrapper + wrapper.findAllComponents('[data-test="number"]'); +}); +``` + +:::warning Utilisation avec des sélecteurs CSS +`findAllComponents` a le même comportement lorsqu'il est utilisé avec un sélecteur CSS tout comme [findComponent](#findcomponent). +::: + +### get + +Récupère un élément et retourne un `DOMWrapper` si trouvé. Renvoie une erreur dans le cas contraire. + +**Signature :** + +```ts +get(selector: K): Omit, 'exists'> +get(selector: K): Omit, 'exists'> +get(selector: string): Omit, 'exists'> +get(selector: string): Omit, 'exists'> +``` + +**Utilisation :** + +Similaire à `find`, mais `get` retourne une exception au lieu de renvoyer un `ErrorWrapper`. + +En règle générale, utilisez toujours `get` sauf lorsque vous vérifiez que quelque chose n'existe pas. Dans ce cas, utilisez `find`. + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('get', () => { + const wrapper = mount(Component); + + wrapper.get('span'); //=> trouvé; retourne DOMWrapper + + expect(() => wrapper.get('.not-there')).toThrowError(); +}); +``` + +### getComponent + +Récupère une instance de composant Vue et renvoie un `VueWrapper` si trouvé. Sinon, il génère une erreur. + +**Signature :** + +```ts +getComponent(selector: new () => T): Omit, 'exists'> +getComponent(selector: { name: string } | { ref: string } | string): Omit, 'exists'> +getComponent(selector: any): Omit, 'exists'> +``` + +**Utilisation :** + +Similaire à `findComponent`, mais `getComponent` retourne une exception au lieu de renvoyer un `ErrorWrapper`. + +**Syntaxes supportées :** + +| Syntaxe | Exemple | Détails | +|------------------|------------------------------|----------------------------------------------------------| +| querySelector | `getComponent('.component')` | Trouve comme à un sélecteur CSS standard. | +| Nom du Composant | `getComponent({name: 'a'})` | Trouve en PascalCase, snake-case et camelCase. | +| Ref du Composant | `getComponent({ref: 'ref'})` | Trouve la reference directe d'un composant enfant monté. | +| SFC | `getComponent(Component)` | Trouve directement un composant importé. | + +`Foo.vue` + +```vue + + + +``` + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +import Foo from '@/Foo.vue'; + +test('getComponent', () => { + const wrapper = mount(Component); + + wrapper.getComponent({ name: 'foo' }); // retourne un VueWrapper + wrapper.getComponent(Foo); // retourne un VueWrapper + + expect(() => wrapper.getComponent('.not-there')).toThrowError(); +}); +``` + +### html + +Renvoie le HTML d'un élément. + +Par défaut, la sortie est formatée avec [`js-beautify`](https://github.com/beautify-web/js-beautify) pour rendre les `snapshots` plus lisibles. Utilisez l'option `raw: true` pour recevoir la chaîne HTML non formatée. + +**Signature :** + +```ts +html(): string +html(options?: { raw?: boolean }): string +``` + +**Utilisation :** + +`Component.vue`: + +```vue + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('html', () => { + const wrapper = mount(Component); + + expect(wrapper.html()).toBe( + '
\n' + + '

Bonjour tout le monde

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

Bonjour tout le monde

'); +}); +``` + +### isVisible + +Vérifie si un élément est visible ou non. + +**Signature :** + +```ts +isVisible(): boolean +``` + +**Utilisation :** + +```js +const Component = { + template: `
`, +}; + +test('isVisible', () => { + const wrapper = mount(Component); + + expect(wrapper.find('span').isVisible()).toBe(false); +}); +``` + +### props + +Retourne les propriétés (`props`) passées à un Composant Vue. + +**Signature :** + +```ts +props(): { [key: string]: any } +props(selector: string): any +props(selector?: string): { [key: string]: any } | any +``` + +**Utilisation :** + +`Component.vue`: + +```js +export default { + name: 'Component', + props: { + truthy: Boolean, + object: Object, + string: String, + }, +}; +``` + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('props', () => { + const wrapper = mount(Component, { + global: { stubs: ['Foo'] }, + }); + + const foo = wrapper.getComponent({ name: 'Foo' }); + + expect(foo.props('truthy')).toBe(true); + expect(foo.props('object')).toEqual({}); + expect(foo.props('notExisting')).toEqual(undefined); + expect(foo.props()).toEqual({ + truthy: true, + object: {}, + string: 'string', + }); +}); +``` + +:::tip +En règle générale, testez les effets d'une `prop` transmise (une mise à jour du DOM, un événement émis, etc.). Cela rendra les tests plus puissants que de simplement vérifier qu'une prop a été transmise. +::: + +### setData + +Met à jour les données internes d'un composant. + +**Signature :** + +```ts +setData(data: Record): Promise +``` + +**Utilisation :** + +`setData` ne permet pas de définir de nouvelles propriétés qui ne sont pas définies dans le composant. + +De plus, notez que `setData` ne modifie pas les données de la fonction l'API de Composition : `setup()`. + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('setData', async () => { + const wrapper = mount(Component); + expect(wrapper.html()).toContain('Compteur: 0'); + + await wrapper.setData({ count: 1 }); + + expect(wrapper.html()).toContain('Compteur: 1'); +}); +``` + +::: warning +Vous devriez utiliser `await` lorsque vous appelez `setData` pour vous assurer que Vue met à jour le DOM avant de faire une vérification. +::: + +### setProps + +Met à jour les `props` d'un composant. + +**Signature :** + +```ts +setProps(props: Record): Promise +``` + +**Utilisation :** + +`Component.vue`: + +```vue + + + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils'; +import Component from './Component.vue'; + +test('met à jour les props', async () => { + const wrapper = mount(Component, { + props: { + message: 'Bonjour' + }, + }); + + expect(wrapper.html()).toContain('Bonjour'); + + await wrapper.setProps({ message: 'Au revoir' }); + + expect(wrapper.html()).toContain('Au revoir'); +}); +``` + +::: warning +Vous devriez utiliser `await` lorsque vous appelez `setProps` pour vous assurer que Vue met à jour le DOM avant de faire une vérification. +::: + +### setValue + +Définit une valeur sur un élément du DOM. Incluant : + +- `` + - `type="checkbox"` et `type="radio"` sont détectés et auront `element.checked` de coché. +- `