From 3986a09458ec85984aa2d697c88257d5a6ccf07e Mon Sep 17 00:00:00 2001 From: phrobinet Date: Tue, 16 Nov 2021 10:05:43 +0100 Subject: [PATCH] add french version --- src/.vuepress/config.js | 76 ++++ src/fr/README.md | 40 ++ src/fr/components-with-props.md | 207 +++++++++ src/fr/composition-api.md | 127 ++++++ src/fr/computed-properties.md | 206 +++++++++ src/fr/finding-elements-and-components.md | 174 ++++++++ src/fr/jest-mocking-modules.md | 20 + src/fr/mocking-global-objects.md | 135 ++++++ src/fr/reducing-boilerplate-in-tests.md | 334 +++++++++++++++ src/fr/rendering-a-component.md | 76 ++++ src/fr/setting-up-for-tdd.md | 214 +++++++++ src/fr/simulating-user-input.md | 278 ++++++++++++ src/fr/stubbing-components.md | 161 +++++++ src/fr/testing-emitted-events.md | 137 ++++++ src/fr/testing-vuex.md | 21 + src/fr/vue-router.md | 405 ++++++++++++++++++ src/fr/vuex-actions.md | 181 ++++++++ src/fr/vuex-getters.md | 100 +++++ ...uex-in-components-mutations-and-actions.md | 171 ++++++++ src/fr/vuex-in-components.md | 201 +++++++++ src/fr/vuex-mutations.md | 100 +++++ src/v3/fr/README.md | 39 ++ src/v3/fr/components-with-props.md | 209 +++++++++ src/v3/fr/composition-api.md | 119 +++++ src/v3/fr/computed-properties.md | 214 +++++++++ src/v3/fr/finding-elements-and-components.md | 175 ++++++++ src/v3/fr/jest-mocking-modules.md | 21 + src/v3/fr/mocking-global-objects.md | 145 +++++++ src/v3/fr/reducing-boilerplate-in-tests.md | 329 ++++++++++++++ src/v3/fr/rendering-a-component.md | 82 ++++ src/v3/fr/setting-up-for-tdd.md | 239 +++++++++++ src/v3/fr/simulating-user-input.md | 288 +++++++++++++ src/v3/fr/stubbing-components.md | 163 +++++++ src/v3/fr/testing-emitted-events.md | 142 ++++++ src/v3/fr/testing-vuex.md | 21 + src/v3/fr/vue-router.md | 376 ++++++++++++++++ src/v3/fr/vuex-actions.md | 187 ++++++++ src/v3/fr/vuex-getters.md | 104 +++++ ...uex-in-components-mutations-and-actions.md | 177 ++++++++ src/v3/fr/vuex-in-components.md | 203 +++++++++ src/v3/fr/vuex-mutations.md | 103 +++++ 41 files changed, 6700 insertions(+) create mode 100644 src/fr/README.md create mode 100644 src/fr/components-with-props.md create mode 100644 src/fr/composition-api.md create mode 100644 src/fr/computed-properties.md create mode 100644 src/fr/finding-elements-and-components.md create mode 100644 src/fr/jest-mocking-modules.md create mode 100644 src/fr/mocking-global-objects.md create mode 100644 src/fr/reducing-boilerplate-in-tests.md create mode 100644 src/fr/rendering-a-component.md create mode 100644 src/fr/setting-up-for-tdd.md create mode 100644 src/fr/simulating-user-input.md create mode 100644 src/fr/stubbing-components.md create mode 100644 src/fr/testing-emitted-events.md create mode 100644 src/fr/testing-vuex.md create mode 100644 src/fr/vue-router.md create mode 100644 src/fr/vuex-actions.md create mode 100644 src/fr/vuex-getters.md create mode 100644 src/fr/vuex-in-components-mutations-and-actions.md create mode 100644 src/fr/vuex-in-components.md create mode 100644 src/fr/vuex-mutations.md create mode 100644 src/v3/fr/README.md create mode 100644 src/v3/fr/components-with-props.md create mode 100644 src/v3/fr/composition-api.md create mode 100644 src/v3/fr/computed-properties.md create mode 100644 src/v3/fr/finding-elements-and-components.md create mode 100644 src/v3/fr/jest-mocking-modules.md create mode 100644 src/v3/fr/mocking-global-objects.md create mode 100644 src/v3/fr/reducing-boilerplate-in-tests.md create mode 100644 src/v3/fr/rendering-a-component.md create mode 100644 src/v3/fr/setting-up-for-tdd.md create mode 100644 src/v3/fr/simulating-user-input.md create mode 100644 src/v3/fr/stubbing-components.md create mode 100644 src/v3/fr/testing-emitted-events.md create mode 100644 src/v3/fr/testing-vuex.md create mode 100644 src/v3/fr/vue-router.md create mode 100644 src/v3/fr/vuex-actions.md create mode 100644 src/v3/fr/vuex-getters.md create mode 100644 src/v3/fr/vuex-in-components-mutations-and-actions.md create mode 100644 src/v3/fr/vuex-in-components.md create mode 100644 src/v3/fr/vuex-mutations.md diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index 10532a4e..d0685c02 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -66,6 +66,14 @@ module.exports = { lang: 'ko', title: 'Vue 테스팅 핸드북', }, + '/fr/': { + lang: 'fr-FR', + title: 'Manuel de test de Vue', + }, + '/v3/fr/': { + lang: 'fr-BE', + title: 'Manuel de test de Vue3' + } }, themeConfig: { repo: 'lmiller1990/vue-testing-handbook', @@ -139,6 +147,74 @@ module.exports = { ['/v3/jest-mocking-modules', 'Jest - mocking modules'], ], }, + '/fr/': { + label: 'Français', + selectText: 'Langues', + lastUpdated: 'Dernière mise à jour', + editLinkText: 'Modifier cette page sur GitHub', + sidebar: [ + ['/fr/', 'Bienvenue'], + ['/fr/setting-up-for-tdd', 'Mise en place de la TDD'], + ['/fr/rendering-a-component', 'Composants de Rendu'], + ['/fr/components-with-props', 'Tester les Props'], + ['/fr/computed-properties', 'Propriétés Calculées'], + ['/fr/simulating-user-input', 'Simulation de l\'entrée utilisateur'], + ['/fr/testing-emitted-events', 'Test des événements émis'], + ['/fr/mocking-global-objects', 'Objets globaux de simulation'], + ['/fr/stubbing-components', 'Stubbing components'], + [ + '/fr/finding-elements-and-components', + 'Recherche l\'éléments et de composants', + ], + ['/fr/testing-vuex', 'Tester Vuex'], + ['/fr/vuex-mutations', 'Vuex - Mutations'], + ['/fr/vuex-actions', 'Vuex - Actions'], + ['/fr/vuex-getters', 'Vuex - Getters'], + ['/fr/vuex-in-components', 'Vuex dans les composants - $state et getters'], + [ + '/fr/vuex-in-components-mutations-and-actions', + 'Vuex dans les composants - mutations and actions', + ], + ['/fr/vue-router', 'Vue Router'], + ['/fr/composition-api', 'Composition API'], + ['/fr/reducing-boilerplate-in-tests', 'Réduire le " Boilerplate "'], + ['/fr/jest-mocking-modules', 'Jest - modules de simulation'], + ], + }, + '/v3/fr/': { + label: 'v3', + selectText: 'Langues', + lastUpdated: 'Dernière mise à jour', + editLinkText: 'Modifier cette page sur GitHub', + sidebar: [ + ['/v3/fr/', 'Bienvenue'], + ['/v3/fr/setting-up-for-tdd', 'Mise en place de la TDD'], + ['/v3/fr/rendering-a-component', 'Composants de rendu'], + ['/v3/fr/components-with-props', 'Tester les Props'], + ['/v3/fr/computed-properties', 'Propriétés calculées'], + ['/v3/fr/simulating-user-input', 'Simulation de l\'entrée utilisateur'], + ['/v3/fr/testing-emitted-events', 'Test des événements émis'], + ['/v3/fr/mocking-global-objects', 'Objets globaux de simulation'], + ['/v3/fr/stubbing-components', 'Stubbing components'], + [ + '/v3/fr/finding-elements-and-components', + 'Recherche d\'éléments et de composants', + ], + ['/v3/fr/testing-vuex', 'Tester Vuex'], + ['/v3/fr/vuex-mutations', 'Vuex - Mutations'], + ['/v3/fr/vuex-actions', 'Vuex - Actions'], + ['/v3/fr/vuex-getters', 'Vuex - Getters'], + ['/v3/fr/vuex-in-components', 'Vuex dans les composants - $state and getters'], + [ + '/v3/fr/vuex-in-components-mutations-and-actions', + 'Vuex dans les composants - mutations and actions', + ], + ['/v3/fr/vue-router', 'Vue Router'], + ['/v3/fr/composition-api', 'Composition API'], + ['/v3/fr/reducing-boilerplate-in-tests', 'Réduire le " Boilerplate "'], + ['/v3/fr/jest-mocking-modules', 'Jest - modules de simulation'], + ], + }, '/ja/': { label: '日本語', selectText: '言語', diff --git a/src/fr/README.md b/src/fr/README.md new file mode 100644 index 00000000..efd7fc59 --- /dev/null +++ b/src/fr/README.md @@ -0,0 +1,40 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Qu'est-ce que ce guide ? + +Bienvenue dans le manuel de test Vue.js ! + + +Il s'agit d'un collection court ciblé sur la façon de tester les composants de Vue Il utilise `vue-test-utils`, la bibliothèque officielle pour tester les composant de Vue et Jest un framework de test moderne. Il couvre l'API `vue-test-utils` ainsi que les meilleures pratiques pour tester les composants. + +Chaque section est indépendante des autres. Nous commençons par créer un environnement avec `vue-cli` et écrire un simple test. Ensuite, nous discuterons des deux possibilités de rendre un composant par `mount` et `shallowMount`. Les différences seront démontrées et expliquées. + +Ensuite, nous verrons comment tester différents scénarios qui se présentent quand nous testerons les composants, comme par exemple : + +- recevoir les "props" +- utiliser les propriétés "computed" +- renvoyer d'autres "composant" +- émettre des événements + +Et ainsi de suite. Nous passerons ensuite à des cas plus intéressants, tels que : + +- les meilleurs pratiques pour tester Vuex (dans les composants et de manière indépendante) +- tester Vue router +- testing involving third party components + +Nous étudierons également comment utiliser les API de Jest pour rendre nos tests plus robustes, par exemple : + +- les réponses mocking API +- les modules mocking et spying +- utiliser snapshots + +## Lectures complémentaires + +Parmi les autres ressources utiles, citons : + +- [La doc officiel](https://vue-test-utils.vuejs.org/) +- [Livre](https://www.manning.com/books/testing-vue-js-applications) écrit par l'un des auteurs de `vue-test-utils` (en anglais) +- Mon [Vue.js 3 + Unit Testing Course](https://vuejs-course.com) (début 2002, les premiers modules en avant-première/révision disponibles) +- [This awesome course on VueSchool](https://vueschool.io/courses/learn-how-to-test-vuejs-components?friend=vth) par plusieurs contributeurs de l'équipe de Vue (en anglais) diff --git a/src/fr/components-with-props.md b/src/fr/components-with-props.md new file mode 100644 index 00000000..468ce20d --- /dev/null +++ b/src/fr/components-with-props.md @@ -0,0 +1,207 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Paramétrez les props avec propsData + +`propsData` peut être utilisé aussi bien avec `mount` que `shallowMount`. Il est souvent utilisé pour tester les composants qui reçoivent les props de leur composant parent. + +`propsData` est passé en deuxième argument de `shallowMount` or `mount`, sous la forme suivante : + +```js +const wrapper = shallowMount(Foo, { + propsData: { + foo: 'bar' + } +}) +``` + +## Création d'un composant + +Créez un simple composant `` qui a deux `props`: `msg` et `isAdmin`. En fonction de la valeur du prop `isAdmin` le `` aura l'un des deux états : + +* `Not Authorized` si `isAdmin` est faux (ou non passé comme prop). +* `Admin Privileges` si `isAdmin` est vrai. + +```html + + + +``` + +## Le premier test + +Nous ferons une affirmation sur le message dans le cas où l'utilisateur n'a pas les privilèges administrateur. + +```js +import { mount } from '@vue/test-utils' +import SubmitButton from '@/components/SubmitButton.vue' + +describe('SubmitButton.vue', () => { + it("displays a non authorized message", () => { + const msg = "submit" + const wrapper = mount(SubmitButton,{ + propsData: { + msg: msg + } + }) + + console.log(wrapper.html()) + + expect(wrapper.find("span").text()).toBe("Not Authorized") + expect(wrapper.find("button").text()).toBe("submit") + }) +}) +``` + +Lancez le test avec `yarn test:unit`. Le résultat est : + +``` +PASS tests/unit/SubmitButton.spec.js + SubmitButton.vue + ✓ displays a non authorized message (15ms) +``` + +Le résultat de `console.log(wrapper.html())` va aussi afficher : + +```html +
+ Not Authorized + +
+``` + +Nous pouvons voir que le prop `msg` est traité et que le résultat est correctement rendu + +## Le deuxième test + +Faisons une autre affirmation dans l'autre état possible, quand `isAdmin` est `true` : + +```js +import { mount } from '@vue/test-utils' +import SubmitButton from '@/components/SubmitButton.vue' + +describe('SubmitButton.vue', () => { + it('displays a admin privileges message', () => { + const msg = "submit" + const isAdmin = true + const wrapper = mount(SubmitButton,{ + propsData: { + msg, + isAdmin + } + }) + + console.log(wrapper.html()) + + expect(wrapper.find("span").text()).toBe("Admin Privileges") + expect(wrapper.find("button").text()).toBe("submit") + }) +}) +``` + +Lancé le test avec `yarn test:unit` et vérifier les résultats : + +```shell +PASS tests/unit/SubmitButton.spec.js + SubmitButton.vue + ✓ displays a admin privileges message (4ms) +``` + +Le résultat de `console.log(wrapper.html())` va aussi s'afficher + +```html +
+ Admin Privileges + +
+``` +Nous pouvons voir que le prop `isAdmin` a été utilisé pour renvoyer le correct `` élément. + +## Refactoriser les tests + +Refactorisons le test en adhérant au principe de "Ne Pas Répétez" (Don't Repeat Yourself (DRY)). Comme tous les tests sont réussis, nous pouvons refactoriser en toute confiance. Tant que tous les tests sont réussis après la refactorisation, nous pouvons être sûrs de n'avoir rien cassé. + +## Refactoriser avec une fonction usine + +Dans les deux tests, nous appelons `mount` puis nous lui passons l’objet `propsData` similaire. Nous pouvons refactoriser en utilisant une fonction usine. Une fonction usine est simplement une fonction qui nous renvoie un objet (elle fait des objets d’où le nom fonction usine). + +```js +const msg = "submit" +const factory = (propsData) => { + return mount(SubmitButton, { + propsData: { + msg, + ...propsData + } + }) +} +``` +Ce qui précède est une fonction qui va " monter " un composant `SubmitButton`. Nous pouvons faire passer n’importe quel props pour changer comme premier argument à `factory`. DRY (Ne Pas Répétez) le test avec la fonction usine. + +```js +describe("SubmitButton", () => { + describe("does not have admin privileges", ()=> { + it("renders a message", () => { + const wrapper = factory() + + expect(wrapper.find("span").text()).toBe("Not Authorized") + expect(wrapper.find("button").text()).toBe("submit") + }) + }) + + describe("has admin privileges", ()=> { + it("renders a message", () => { + const wrapper = factory({ isAdmin: true }) + + expect(wrapper.find("span").text()).toBe("Admin Privileges") + expect(wrapper.find("button").text()).toBe("submit") + }) + }) +}) +``` +Recommençons les tests. Tout passe encore + +```sh +PASS tests/unit/SubmitButton.spec.js + SubmitButton + has admin privileges + ✓ renders a message (26ms) + does not have admin privileges + ✓ renders a message (3ms) +``` + +Puisque nous avons une suite de test réussi, nous pouvons maintenant facilement et en tout confiance refactoriser + +## Conclusion + +- En passant `propsData` lors d'un montage d'un composant, nous pouvons définir les `props` à utiliser dans le test. +- Les fonctions usines peuvent être utilisées pour DRY (Ne pas Répétez) les tests +- Au lieu de `propsData`, vous pouvez aussi utiliser [`setProps`](https://vue-test-utils.vuejs.org/api/wrapper-array/#setprops-props) pour définir les valeurs des props pendant les tests. diff --git a/src/fr/composition-api.md b/src/fr/composition-api.md new file mode 100644 index 00000000..725a6ab9 --- /dev/null +++ b/src/fr/composition-api.md @@ -0,0 +1,127 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## La Composition API + +Vue 3 va introduire une nouvelle API pour la création de composants - [Composition API](https://vue-composition-api-rfc.netlify.com/#basic-example). Pour permettre aux utilisateurs de l'essayer et d'obtenir des commentaires, l'équipe Vue a publié un plugin qui nous permet de l'essayer dans Vue2. Vous pouvez le trouvez [ici](https://github.com/vuejs/composition-api). + +Tester la construction d'un composant avec Composition API ne devrait pas être de tester un composant standard, puisque que nous ne testons pas l'implémentation, mais la sortie (*ce que* le composant fait , et pas *comment* il le fait). Cet article montre un exemple simple d'un composant utilisant le Compostion API dans Vue 2, et comment les stratégies de test sont les mêmes que pour tout autre composant. + +Le code source pour le test décrit dans cette page peut être trouvé [ici](https://github.com/lmiller1990/vue-testing-handbook/tree/master/demo-app/tests/unit/CompositionApi.spec.js). + +## Le Composant + +Sous-le "Hello, World" de la Composition API, plus ou moins. Si vous ne comprenez pas quelque chose, [lisez le RFC](https://vue-composition-api-rfc.netlify.com/) ou allez sur Google; il existe de nombreuses ressources sur la Composition API. + +```html + + + +``` + +Les deux choses que nous devrons tester ici sont : + +1. Le fait de cliquer sur le bouton d'incrémentation augmente-t-il de 1 le `state.count` ? + +2. Le message reçu dans les props est-il rendu correctement (transformé en majuscules) ? + +## Tester le Message des Props +Il est évident de vérifier que le message est correctement rendu. Nous utilisons simplement "propsData" pour définir la valeur du prop, comme décrit [ici](/components-with-props.html). + + +```js +import { mount } from "@vue/test-utils" + +import CompositionApi from "@/components/CompositionApi.vue" + +describe("CompositionApi", () => { + it("renders a message", () => { + const wrapper = mount(CompositionApi, { + propsData: { + message: "Testing the composition API" + } + }) + + expect(wrapper.find(".message").text()).toBe("TESTING THE COMPOSITION API") + }) +}) +``` +Comme prévu, c'est très simple : quelle que soit la façon dont nous créons les composants, nous utilisons la même API et la même stratégie pour les tests. Vous devriez pourvoir modifier entièrement l'implémentation et ne pas avoir besoin de toucher aux tests. N'oubliez pas de tester les sorties (le rendu HTML, en général) en fonction des entrées données (accessoires, événements déclenchés), et non de l'implémentation. + +## Tester le Bouton Clic + +Faire un test pour s'assurer que le fait de cliquer sur le bouton augmente le `state.count` est tout aussi simple. Notez que le test est marqué `async` ; pour en savoir plus sur les raisons de cette exigence, consulter [Simulating User Input](simulating-user-input.html#writing-the-test). + +```js +import { mount } from "@vue/test-utils" + +import CompositionApi from "@/components/CompositionApi.vue" + +describe("CompositionApi", () => { + it("increments a count when button is clicked", async () => { + const wrapper = mount(CompositionApi, { + propsData: { message: '' } + }) + + wrapper.find('button').trigger('click') + await wrapper.vm.$nextTick() + + expect(wrapper.find(".count").text()).toBe("Count: 1") + }) +}) +``` +Encore une fois - nous `déclenchons` l'événement clic, et nous voyons que le rendu `count` a augmenté + +## Conclusion + +L'article montre comment le teste d'un composant à l'aide Composition API est identique au test d'un composant à l'aide de l'option traditionnelles de l'API. Les idées et les concepts sont les mêmes. Le point principal à apprendre est que lors de la rédaction des tests, il faut faire des affirmations basées sur les entrées et les sorties. + + +Il devrait être possible de re-factoriser n'importe quel composant traditionnel de Vue pour utiliser le Component API sans avoir à modifier les tests unitaires. Si vous devez modifier vos tests lors de la refonte, vous testez probablement l'implémentation" et non la sortie. + +Bien qu'il s'agisse d'une nouvelle fonctionnalité passionnante, l'API de composition est entièrement additive, il n'y a donc pas de besoin immédiat de l'utiliser. Cependant, quel que soit votre choix, rappelez-vous qu'un bon test unitaire affirme l'état final du composant, sans tenir compte des détails de l'implémentation. diff --git a/src/fr/computed-properties.md b/src/fr/computed-properties.md new file mode 100644 index 00000000..487f1006 --- /dev/null +++ b/src/fr/computed-properties.md @@ -0,0 +1,206 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Tester la propriété Computed + +Vous pouvez trouver le test décrit sur cette page [ici](https://github.com/lmiller1990/vue-testing-handbook/tree/master/demo-app/tests/unit/NumberRenderer.spec.js). + +Le test des propriétés computed sont particulièrement simple, puisqu'il s'agit de bon vieux JavasScript. + +Commençons par examiner deux façons de tester la propriété `computed`. Nous allons développer un composant ``, qui rend les nombres pairs ou impairs, basé sur une propriété computed `numbers` + + +## Ecrire le test + +Le composant `` va recevoir un prop `even` qui est un booléen. Si `even` est `true`, le composant devrait renvoyer 2, 4, 6 et 8. S'il est `false`, il devrait renvoyer 1, 3, 5, 7 et 9. la liste des valeurs va être calculer dans la propriété `computed` appeler `numbers`. + +## Tester en renvoyant la valeur + +Le test : + +```js +import { mount } from "@vue/test-utils" +import NumberRenderer from "@/components/NumberRenderer.vue" + +describe("NumberRenderer", () => { + it("renders even numbers", () => { + const wrapper = mount(NumberRenderer, { + propsData: { + even: true + } + }) + + expect(wrapper.text()).toBe("2, 4, 6, 8") + }) +}) +``` +Avant de lancer le test, configurons ``: + +```js + + + +``` +Maintenant commençons le développement, et laissons les messages d'erreur guider notre implémentation. `yarn test:unit`: + +``` +● NumberRenderer › renders even numbers + + expect(received).toBe(expected) // Object.is equality + + Expected: "2, 4, 6, 8" + Received: "" +``` +Il semble que tout soit bien an place. Commençons à implémenter `numbers`: + +```js +computed: { + numbers() { + const evens = [] + + for (let i = 1; i < 10; i++) { + if (i % 2 === 0) { + evens.push(i) + } + } + + return evens + } +} +``` +Et de mettre à jour notre modèle pour utiliser notre nouvelle propriété computed : +```html + +``` + +Maintenant `yarn test:unit` nous renvoie : + +``` +FAIL tests/unit/NumberRenderer.spec.js +● NumberRenderer › renders even numbers + + expect(received).toBe(expected) // Object.is equality + + Expected: "2, 4, 6, 8" + Received: "[ + 2, + 4, + 6, + 8 + ]" +``` +Les nombres sont correct, mais nous voulons que la liste soit bien formatée. Mettons à jour la valeur de `retour` : + +```js +return evens.join(", ") +``` + +Maintenant `yarn test:unit` passe! + +## Tester avec `call` + +Nous allons maintenant ajouter le test pour le cas ou `even: false`. Cette fois, nous allons voir une autre façon de tester la propriété computed, sans renvoyer réellement un composant. + +Le test, d'abord: + +```js +it("renders odd numbers", () => { + const localThis = { even: false } + + expect(NumberRenderer.computed.numbers.call(localThis)).toBe("1, 3, 5, 7, 9") +}) +``` +Au lieu de renvoyer le composant et de faire une affirmation sur `wrapper.text()`, nous allons utiliser `call` pour fournir un contexte alternatif à `this`. Nous allons voir ce qui se passe si nous n'utilisons pas `call` après avoir réussi le test. + +L’exécution du test nous donner des résultats : + +``` +FAIL tests/unit/NumberRenderer.spec.js +● NumberRenderer › renders odd numbers + + expect(received).toBe(expected) // Object.is equality + + Expected: "1, 3, 5, 7, 9" + Received: "2, 4, 6, 8" +``` + +La mise à jour de`numbers` : + + +```js +numbers() { + const evens = [] + const odds = [] + + for (let i = 1; i < 10; i++) { + if (i % 2 === 0) { + evens.push(i) + } else { + odds.push(i) + } + } + + return this.even === true ? evens.join(", ") : odds.join(", ") +} +``` +Maintenant nos deux tests passent ! Mais que ce serait-il passé si nous n'avions pas utilisé `call` dans le deuxième test ? Essayez de le mettre à jour comme ceci : + +```js +it("renders odd numbers", () => { + const localThis = { even: false } + + expect(NumberRenderer.computed.numbers()).toBe("1, 3, 5, 7, 9") +}) +``` + +Le test échoue maintenant : + +``` +FAIL tests/unit/NumberRenderer.spec.js +● NumberRenderer › renders odd numbers + + expect(received).toBe(expected) // Object.is equality + + Expected: "1, 3, 5, 7, 9" + Received: "2, 4, 6, 8" +``` + +`vue` lie automatiquement `props` à `this`. Nous ne renvoyons pas le composant avec `mount`, donc Vue le lie rien à `this`. Si vous faite un `console.log(this)`, vous pouvez voir que le contexte est simplement l’objet `computed` : + +``` +{ numbers: [Function: numbers] } +``` +Donc nous avons besoin d'utiliser `call`, qui nous permet de lier l'objet `this`, dans notre cas avec la propriété `even`. + +## Pour `call` ou pour `mount`? +Ces deux techniques présentées sont utiles pour tester les propriétés computed. `call` peut être utile quand : + +- Vous testez un composant qui effectue des opérations qui prennent du temps dans un cycle de vie et que vous aimeriez éviter de l'exécuter dans votre test unitaire computed. +- Vous voulez mettre en avant certaines valeurs sur `this`. En utilisant `call` et passer un contexte personnalisé peut être utile. + +Bien sûr, vous voulez être sûr que la valeur est correctement renvoyé, alors assurez-vous de choisir la bonne technique quand vous testerez vos propriétés computed et de tester tous les cas. + + +## Conclusion + +- Les propriétés computed peuvent être utilisées en utilisant `mount` en faisant des affirmations sur le rendu du code. +- Les propriétés complexes de computed peuvent être testées indépendamment en utilisant `call`. diff --git a/src/fr/finding-elements-and-components.md b/src/fr/finding-elements-and-components.md new file mode 100644 index 00000000..b660c7ff --- /dev/null +++ b/src/fr/finding-elements-and-components.md @@ -0,0 +1,174 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Trouver des éléments + + +`vue-test-utils` fournit un certain nombre de possibilité pour trouver et affirmer la présence d'élément HTML ou d'autres composants Vue en utilisant la méthode `find`. L'utilisation principale de `find` est d'affirmer qu'un composant rend correctement un élément ou un composant enfant. + + +Le code source du test décrit sur cette page peut être trouvé [ici](https://github.com/lmiller1990/vue-testing-handbook/tree/master/demo-app/tests/unit/Parent.spec.js). + +## Le création de composants + +Pour cet exemple, nous allons créer un composant `` et un ``. + +Child: + +```vue + + + +``` + +Parent: + +```vue + + + +``` + +## `find` avec la syntaxe `querySelector` + +Les éléments réguliers peuvent facilement être sélectionner en utilisant la syntaxe utilisée avec `document.querySlector`. `vue-test-utils` fournit la méthode `isVisible` qui vérifie si les éléments rendus conditionnellement avec `v-show` sont visibles. Créer un fichier `Parent.spec.js` et à l'intérieur ajouter le test suivant : + +```js +import { mount } from "@vue/test-utils" +import Parent from "@/components/Parent.vue" + +describe("Parent", () => { + it("does not render a span", () => { + const wrapper = mount(Parent) + + expect(wrapper.find("span").isVisible()).toBe(false) + }) +}) +``` +Puisque `v-show="showSpan"` est par défaut `false`, nous espérons trouver `false` à la méthode `isVisible` de l'élément ``. Les tests passent quand nous exécutons `yarn test:unit`. Ensuite, un test avec le cas `showSpan` est `true`. + +```js +it("does render a span", () => { + const wrapper = mount(Parent, { + data() { + return { showSpan: true } + } + }) + + expect(wrapper.find("span").isVisible()).toBe(true) +}) +``` +Ça passe ! Tout comme `isVisible` pour `v-show`, `vue-test-utils` fournit une méthode à utiliser quand nous devons tester le rendu conditionnel de l'élément en utilisant `v-if`. + + +## Trouver des composants avec `name` et `Component` + +Trouver des composants enfants est légèrement différent qu'avec des éléments HTML. Il y a deux façons principales d'affirmer la présence des composants enfants : + +1. `find(Component)` +2. `find({ name: "ComponentName" })` + +C'est un peu plus facile à comprendre dans le contexet d'un exemple. Commençons avec la syntaxe `find(Component)`. Cela nous oblige d'importer le composant et à le passer par la fonction `find`. + + +```js +import Child from "@/components/Child.vue" + +it("does not render a Child component", () => { + const wrapper = mount(Parent) + + expect(wrapper.find(Child).exists()).toBe(false) +}) +``` +L'implémentation pour `find` est un peu plus complexe, depuis qu'il fonctionne avec la syntaxe `querySelector`, aussi bien qu'avec d'autres syntaxes. Vous pouvez voir la partie du code source du composant enfant [ici](https://github.com/vuejs/vue-test-utils/blob/dev/packages/test-utils/src/find.js). Il vérifie simplement que le nom `name` du composant sur chaque enfant retourné, puis vérifie le `constuctor` et quelques autres propriétés. + + + +Comme mentionné dans le paragraphe précédent, la propriété `name` et l'une des vérifications faites avec `find` quand vous passez un composant. Au lieu de passer le composant, vous pouvez simplement passer un objet avec la propriété `name` correcte. Cela signifie que vous n'avez pas d'importer le composant. Testons le cas où ``devrait être rendu : + + +```js +it("renders a Child component", () => { + const wrapper = mount(Parent, { + data() { + return { showChild: true } + } + }) + + expect(wrapper.find({ name: "Child" }).exists()).toBe(true) +}) +``` +Ça passe ! Utiliser la propriété `name` peut être un peu contre intuitive, donc importer le composant réel est une alternative. Une autre option est simplement d'ajouter une `class` ou un `id` et d'utiliser une requête en utilisant la syntaxe `querySelector` présentée dans les deux premiers exemples. + +## `findAll` + +Il y a souvent des cas où l'on veut affirmer qu'un certain d'éléments sont rendus. Un cas courant est une liste d'éléments rendu avec `v-for`. Voici un composant ``. + + +```js + + + +``` +Nous pouvons écrire un test en utilisant `findAll` pour affirmer que trois composants `` sont rendus comme ceci : + +```js +it("renders many children", () => { + const wrapper = mount(ParentWithManyChildren) + + expect(wrapper.findAll(Child).length).toBe(3) +}) +``` + +L'utilisation de `yarn test:unit` montre que le test est réussi. Vous pouvez également utiliser la syntaxe `querySelector` avec `findAll` + +## Conclusion + +Cette page couvre : + +- L'utilisation de `find`et de `findAll` avec la syntaxe de `querySlector` +- `isVisible` et `exists` +- L'utilisation de `find` et de `findAll` avec un composant ou un `name` comme sélecteur. + +Le code source du test décrit sur cette page peut être trouvé [ici](https://github.com/lmiller1990/vue-testing-handbook/tree/master/demo-app/tests/unit/Parent.spec.js). diff --git a/src/fr/jest-mocking-modules.md b/src/fr/jest-mocking-modules.md new file mode 100644 index 00000000..aee12a92 --- /dev/null +++ b/src/fr/jest-mocking-modules.md @@ -0,0 +1,20 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Les Modules de Simulations (Mock) + +TODO : Écrivez cet article. Intéressé ? Ouvrez une issue, et bavardons ! + +Pas directement lié au test de Vue, mais plus spécifique à Jest. Jest est très utilisé dans ce manuel et devient largement adopté par l'industrie, donc je pense qu'il mérite une section. + +Quelques idées : +1. Faire référence aux sections du guide existant en utilisant Jest. +2. Parlez des différents types de mock et de leurs cas d'utilisation pour les tests de Vue. + +- Manual mocks +- ES6 class mocks +- automatic mock +- calling `mockImplentation`? + +Ref: https://jestjs.io/docs/en/es6-class-mocks#the-4-ways-to-create-an-es6-class-mock diff --git a/src/fr/mocking-global-objects.md b/src/fr/mocking-global-objects.md new file mode 100644 index 00000000..dd5eb23a --- /dev/null +++ b/src/fr/mocking-global-objects.md @@ -0,0 +1,135 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Simuler un objet global + +`vue-test-utils` fournit une façon simple de simuler un objet global en attaché à `Vue.prototype`, à la fois sur un test de base et établir une simulation par défaut pour tous les tests. +`vue-test-utils` fournit un moyen simple de simuler des objets globaux attachés à `Vue.prototype`, à la fois test par test et pour définir une maquette par défaut pour tous les tests. + +Le test utilisé dans l'exemple suivant peut être trouvé [ici](https://github.com/lmiller1990/vue-testing-handbook/blob/master/demo-app/tests/unit/Bilingual.spec.js). + +## L'option de montage des simulateurs + +L'option de montage des simulateurs ([mocks mounting option](https://vue-test-utils.vuejs.org/api/options.html#mocks)) est un moyen pour attacher la valeur de toutes les propriétés à `Vue.prototype`. Cela comprend généralement : + +- `$store`, pour Vuex +- `$router`, pour Vue Router +- `$t`, pour vue-i18n + +Et bien d'autres encore. + +## Un exemple avec vue-i18n + +L'utilisation avec Vuex et Vue Router sont abordés dans les sections respectives, [ici](./vuex-in-components.md) et [ici](./vue-router.md). Voyons un exemple avec [vue-i18n](https://github.com/kazupon/vue-i18n). Il serait possible d'utiliser `createLovalVue` et d'installer `vue-i18n` pour chaque test, mais cela deviendrait rapidement encombrant et introduiraot beaucoup d'éléments inutiles. Tout d'abord, un composant `` qui utilise `vue-i18n`: + +```html + + + +``` +Le fonctionnement de `vue-i18n` est de déclarer votre traduction dans un autre fichier, puis de le référencer avec `$t`. Pour les besoins de ce test, l'aspect du fichier de traduction n'a pas beaucoup d'importance, mais pour ce composant il pourra ressembler à ceci : + +```js +export default { + "en": { + helloWorld: "Hello world!" + }, + "ja": { + helloWorld: "こんにちは、世界!" + } +} +``` +En fonction du lieu, la traduction correcte est rendue. Essayons de rendre le composant dans un test, sans simulation : + +```js +import { mount } from "@vue/test-utils" +import Bilingual from "@/components/Bilingual.vue" + +describe("Bilingual", () => { + it("renders successfully", () => { + const wrapper = mount(Bilingual) + }) +}) +``` + +L'exécution de ce test avec `yarn test:unit` renvoie beaucoup d'erreur. Si vous regardez attentivement, vous pouvez voir : + +``` +[Vue warn]: Error in config.errorHandler: "TypeError: _vm.$t is not a function" +``` + +C'est parce que nous n'avons pas installer `vue-i18n`, donc la méthode globale `$t` n'existe pas. Faisons une simulation en utilisant l'option de montage `mocks` : + +```js +import { mount } from "@vue/test-utils" +import Bilingual from "@/components/Bilingual.vue" + +describe("Bilingual", () => { + it("renders successfully", () => { + const wrapper = mount(Bilingual, { + mocks: { + $t: (msg) => msg + } + }) + }) +}) +``` + +Maintenant le test passe ! Il y a beaucoup d'option pour `mocks` à utiliser. Le plus souvent, je me retrouve à simuler les objets globaux qui provient des trois paquets mentionnés ci-dessus. + +## Régler les simulations par défaut en utilisant config + +Parfois vous voulez avoir une valeur par défaut pour la simulation, donc vous ne la créez pas dans un test par un test basique. Vous pouvez utiliser l'API de [config](https://vue-test-utils.vuejs.org/api/#vue-test-utils-config-options) fournie par `vue-test-utils`. Développons l'exemple `vue-i18n`. Vous pouvez définit des modèles par défaut n'importe où en faisant ce qui suit : + +```js +import { config } from "@vue/test-utils" + +config.mocks["mock"] = "Default Mock Value" +``` +Le projet de démo de ce guide utilise Jest, je vais donc déclarer la simulation (mock) par défaut dans `jest.init.js`, qui est chargé avant que les tests ne soient exécutés automatiquement. Je vais également importer l'exemple de notre objet de traduction, et l'utiliser en l'implémentant dans notre simulation. + +```js +import VueTestUtils from "@vue/test-utils" +import translations from "./src/translations.js" + +const locale = "en" + +VueTestUtils.config.mocks["$t"] = (msg) => translations[locale][msg] +``` +Maintenant, une véritable traduction sera rendue, malgré l'utilisation de la fonction `$t`. Refaite le test, cette fois en utilisant `console.log` sur`wrapper.html()` et en retirant l'option de montage `mocks`: + + +```js +describe("Bilingual", () => { + it("renders successfully", () => { + const wrapper = mount(Bilingual) + + console.log(wrapper.html()) + }) +}) +``` +Le test passes, et nous pouvons voir le code qui est rendu : + +``` +
+ Hello world! +
+``` +Vous pouvez lire des informations sur l'utilisation de `mocks` pour tester Vuex [ici](https://lmiller1990.github.io/vue-testing-handbook/vuex-in-components.html#using-a-mock-store). La technique est la même. + +## Conclusion + +Nous avons vu : + + +- L'utilisation de `mocks`pour simuler l'objet global dans un test de base. +- L'utilisation de `config.mocks` pour définir un model par défaut diff --git a/src/fr/reducing-boilerplate-in-tests.md b/src/fr/reducing-boilerplate-in-tests.md new file mode 100644 index 00000000..10f1365d --- /dev/null +++ b/src/fr/reducing-boilerplate-in-tests.md @@ -0,0 +1,334 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Réduire le nombre d'essais + +> Cette article est disponible en screencast sur [Vue.js Courses](https://vuejs-course.com/screencasts/reducing-duplication-in-tests). Consultez le [ici](https://vuejs-course.com/screencasts/reducing-duplication-in-tests). + +L'idéal est souvent de commencer le test unitaire avec une nouvelle copie d'un composant. +De plus, à mesure que vos applications deviennent plus grandes et plus complexes, il y a des chances que vous ayez des composants avec beaucoup de props différents et éventuellement un nombre de librairie tierce telle que Vuetify, VueRouter et Vuex. Cela peut entrainer l'apparition d'un grand nombre de code passe-partout, c'est à dire de code qui n'est pas directement en relation avec le test. + +Dans cet article, on utilise Vuex et VueRouter et on vous montre quelques modèles pour vous aider à réduire la quantité de code + + +Le code source du test décrit sur cette page peut être trouvé [ici](https://github.com/lmiller1990/vue-testing-handbook/tree/master/demo-app/tests/unit/Posts.spec.js). + + +## Le composant Post + +Voici le composant que nous allons tester. Il affiche un prop `message`, s'il en reçoit un. Il affiche un bouton 'Nouveau Post' si l'utilisateur est identifié ainsi que les postes. A la fois les objets `authentication` et `posts` viennent du store de Vuex. Finalement, il rend des composants `router-link` avec un lien vers le post qu'il affiche. + +```vue + + + +``` + +Nous voulons tester : + +- Le `message` est-il rendu quand le prop est reçu ? +- Les `posts` sont-ils correctement rendus ? +- Le bouton 'New Post' est-il présent quand `autenticated` est `true`, caché quand `false` ? + +Idéalement, les tests devraient être aussi concis que possible. + +## Les Fonctions Usines de Vuex/VueRouter + +Une bonne direction à prendre pour rendre l'application plus testable est d'exporter les fonctions usines de Vuex et de VueRouter. Souvent, vous verrez quelque chose comme ceci : + +```js +// store.js + +export default new Vuex.Store({ ... }) + +// router.js +export default new VueRouter({ ... }) +``` + +C'est bien pour une application régulière, mais pas idéale pour les tests. Si vous faite cela, chaque fois que vous utiliserez le store de Vuex ou Router dans un test, il sera partagé avec tous les autres tests qui l'importent également. Idéalement, chaque composant devrait avoir une copie du store et de router. + +Un moyen simple de contourner ce problème consiste à exporter une fonction usine - c'est-à-dire une fonction qui renvoie une nouvelle instance de l'objet. Par example: + +```js +// store.js +export const store = new Vuex.Store({ ... }) +export const createStore = () => { + return new Vuex.Store({ ... }) +} + +// router.js +export default new VueRouter({ ... }) +export const createRouter = () => { + return new VueRouter({ ... }) +} +``` +Maintenant votre application peut importer le store `import { store } from './store.js'` et vos tests peuvent obtenir une nouvelle copie du store à chaque fois en faisant `import { createStore } from './store.js'`, puis de créer l'instance avec `const store = createStore()`. Il en va de même pour le router. C'est ce que je fais dans l'exemple `Posts.vue` - vous trouverez le code pour le store [ici](https://github.com/lmiller1990/vue-testing-handbook/tree/master/demo-app/src/createStore.js) et pour le router [ici](https://github.com/lmiller1990/vue-testing-handbook/tree/master/demo-app/src/createRouter.js). + + +## Les Test (avant refactorisation) + +Maintenant que nous savons à quoi ressemble `Posts.vue`, le store et le router, nous pouvons comprendre ce que font les tests : + +```js +import Vuex from 'vuex' +import VueRouter from 'vue-router' +import { mount, createLocalVue } from '@vue/test-utils' + +import Posts from '@/components/Posts.vue' +import { createRouter } from '@/createRouter' +import { createStore } from '@/createStore' + +describe('Posts.vue', () => { + it('renders a message if passed', () => { + const localVue = createLocalVue() + localVue.use(VueRouter) + localVue.use(Vuex) + + const store = createStore() + const router = createRouter() + const message = 'New content coming soon!' + const wrapper = mount(Posts, { + propsData: { message }, + store, router, + }) + + expect(wrapper.find("#message").text()).toBe('New content coming soon!') + }) + + it('renders posts', async () => { + const localVue = createLocalVue() + localVue.use(VueRouter) + localVue.use(Vuex) + + const store = createStore() + const router = createRouter() + const message = 'New content coming soon!' + + const wrapper = mount(Posts, { + propsData: { message }, + store, router, + }) + + wrapper.vm.$store.commit('ADD_POSTS', [{ id: 1, title: 'Post' }]) + await wrapper.vm.$nextTick() + + expect(wrapper.findAll('.post').length).toBe(1) + }) +}) +``` + +Cela ne teste pas complètement toutes les conditions ; c'est début mais suffisant pour nous permettre de démarrer. Remarquez la duplication et la répétition - débarrassons-nous de cela. + +## Une Fonction Personnalisé `createTestVue` + +Les cinq premières lignes de chaque test sont les mêmes : + +```js +const localVue = createLocalVue() +localVue.use(VueRouter) +localVue.use(Vuex) + +const store = createStore() +const router = createRouter() +``` +Réglons cela. Pour ne pas être confondu avec la fonction `createLocalVue` de Vue Test Utils, j'aime appeler ma fonction `createTestVue`. Elle ressemble un peu à cela : + +```js +const createTestVue = () => { + const localVue = createLocalVue() + localVue.use(VueRouter) + localVue.use(Vuex) + + const store = createStore() + const router = createRouter() + return { store, router, localVue } +} +``` +Maintenant que nous avons encapsuler toute la logique dans une simple fonction. Nous retournons `store`, `router` et `localeVue` depuis que nous devons les passer à la fonction `mount`. + +Si nous refactorisons le premier test en utilisant `createTestVue`, cela ressemblera à ceci : + +```js +it('renders a message if passed', () => { + const { localVue, store, router } = createTestVue() + const message = 'New content coming soon!' + const wrapper = mount(Posts, { + propsData: { message }, + store, + router, + localVue + }) + + expect(wrapper.find("#message").text()).toBe('New content coming soon!') +}) +``` +Un peu plus concis. Refactorisons le second test, qui utilise le store de Vuex. + +```js +it('renders posts', async () => { + const { localVue, store, router } = createTestVue() + const wrapper = mount(Posts, { + store, + router, + }) + + wrapper.vm.$store.commit('ADD_POSTS', [{ id: 1, title: 'Post' }]) + await wrapper.vm.$nextTick() + + expect(wrapper.findAll('.post').length).toBe(1) +}) +``` + +## Définir une méthode `createWrapper` + +Bien que le code ci-dessus soit définitivement une amélioration, en comparaison avec le test précédent, nous pouvons remarquer que la moitié du code est encore dupliqué. Créons une nouvelle méthode, `createWrapper`, pour résoudre ce problème. + +```js +const createWrapper = (component, options = {}) => { + const { localVue, store, router } = createTestVue() + return mount(component, { + store, + router, + localVue, + ...options + }) +} +``` +Maintenant nous allons juste appelé `createWrapper` et avoir une nouvelle copie du composant, prête à être testée. Nos tests sont vraiment concis maintenant. + +```js +it('renders a message if passed', () => { + const message = 'New content coming soon!' + const wrapper = createWrapper(Posts, { + propsData: { message }, + }) + + expect(wrapper.find("#message").text()).toBe('New content coming soon!') +}) + +it('renders posts', async () => { + const wrapper = createWrapper(Posts) + + wrapper.vm.$store.commit('ADD_POSTS', [{ id: 1, title: 'Post' }]) + await wrapper.vm.$nextTick() + + expect(wrapper.findAll('.post').length).toBe(1) +}) +``` + +## Définir le state initial de Vuex + +La dernière amélioration que nous pouvons faire est la façon éditer le store de Vuex. Dans une application réelle, votre store sera probablement plus complexe, et devoir faire beaucoup de mutations et des actions avec des `commit` et des `dispatch` afin de mettre son composant dans l'état que vous voulez n'est pas l'idéal. Nous pouvons faire de petit changement dans notre fonction `createStore`, qui facilitera la définition de notre state initial. + +```js +const createStore = (initialState = {}) => new Vuex.Store({ + state: { + authenticated: false, + posts: [], + ...initialState + }, + mutations: { + // ... + } +}) +``` +Nous pouvons maintenant mettre l'état initial souhaité dans la fonction `createStore`. Nous pouvons faire une rapide refactorisation, en fusionnant `createTestVue` et `createWrapper`. + +```js +const createWrapper = (component, options = {}, storeState = {}) => { + const localVue = createLocalVue() + localVue.use(VueRouter) + localVue.use(Vuex) + const store = createStore(storeState) + const router = createRouter() + + return mount(component, { + store, + router, + localVue, + ...options + }) +} +``` +Maintenant notre test peut être écris comme ceci : + +```js +it('renders posts', async () => { + const wrapper = createWrapper(Posts, {}, { + posts: [{ id: 1, title: 'Post' }] + }) + + expect(wrapper.findAll('.post').length).toBe(1) +}) +``` +C'est une grande amélioration ! Nous sommes passés d'un test où environ la moitié du code était standard et pas réellement lié à l'affirmation, à deux lignes ; une pour préparer le composant au test et une autre pour l'affirmation. + +Un autre avantage de ce remaniement est nous avons une fonction flexible `createWrapper`, que nous pouvons utiliser pour tous nos tests. + + + +## Améliorations + +Il y a d'autres améliorations possibles : + +- mise à jour de la fonction `createStore` pour permettre de définir l'état initial des modules Vuex avec l'espacement des noms (namespacing) +- améliorer `createRouter` pour définir des routes spécifiques +- Permettre à l'utilisateur de passer un `shallow` ou un `mount` comme argument à `createWrapper`. + + +## Conclusion + +Nous avons vu dans cette partie : + +- L'utilisation des fonctions usines afin d'obtenir une nouvelle instance d'un objet. +- Réduire les doublons et les doubles emplois en extrayant les comportements communs. + +Le code source du test décrit sur cette page peut être trouvé [ici](https://github.com/lmiller1990/vue-testing-handbook/tree/master/demo-app/tests/unit/Posts.spec.js). Il est également disponible sous forme d'un screencast sur [Vue.js Courses](https://vuejs-course.com/screencasts/reducing-duplication-in-tests). diff --git a/src/fr/rendering-a-component.md b/src/fr/rendering-a-component.md new file mode 100644 index 00000000..c4a6bca6 --- /dev/null +++ b/src/fr/rendering-a-component.md @@ -0,0 +1,76 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Deux façons de rendre + +`vue-test-utils` fournit deux façons de rendre ou de __monter__ un composant `mount`et `shallowMount`. Un composant monté en utilisant une de ces deux méthodes renvoie un `wrapper`, qui est un objet contenant le composant Vue, plus quelques méthodes pour les tests. + +Commençons avec deux simples composants : + +```js +const Child = Vue.component("Child", { + name: "Child", + + template: "
Child component
" +}) + +const Parent = Vue.component("Parent", { + name: "Parent", + + template: "
" +}) +``` +Commençons par rendre le `Child` et appelant la méthode HTML que `vue-test-utils` nous fournit en inspectant le code. + +```js +const shallowWrapper = shallowMount(Child) +const mountWrapper = mount(Child) + +console.log(shallowWrapper.html()) +console.log(mountWrapper.html()) +``` +Les deux fonctions `mountWrapper.html()` et `shallowWrapper.html()` donnent le résultat suivant: + + +```html +
Child component
+``` +Pas de différence ici. Et pourquoi pas avec `Parent` ? + +```js +const shallowWrapper = shallowMount(Parent) +const mountWrapper = mount(Parent) + +console.log(shallowWrapper.html()) +console.log(mountWrapper.html()) +``` + +`mountWrapper.html()` donne maintenant le résultat : + +```html +
Child component
+``` +Ce qui complète le code `Parent` et `Child`. Par contre, `shallowWrapper.html()` produit ceci : + +```html +
+``` +L'endroit où `` doit être remplacé par ``. `shallowMount` rend les éléments html normaux, mais remplace les composants Vue avec stub. + +> Un stub est une sorte de "faux" objet qui se substitue à un vrai. + +Cela peut être utile. Imaginez que vous vouliez tester votre composant `App.vue`, qui ressemble à ceci : + +```vue + +``` + +Et nous voulons tester que `

My Vue App

` soit correctement rendu. Nous avons aussi un composant `` qui fait une requête à une API externe dans son crochet la vie `mounted` + +Si nous utilisons `mount`, bien que tout ce que nous voulions faire soit d'affirmer qu'un certain texte est rendu, ``, fera une requête API. Cela rendra notre test lent avec de possible échec. Donc nous éliminons les dépendances externes. En utilisant `shallowMount`, `` sera remplacé par ``, et l'appel API ne sera pas lancé. diff --git a/src/fr/setting-up-for-tdd.md b/src/fr/setting-up-for-tdd.md new file mode 100644 index 00000000..2e0b54f5 --- /dev/null +++ b/src/fr/setting-up-for-tdd.md @@ -0,0 +1,214 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Installation de vue-cli + +`vue-test-utils` est la librairie officielle de test pour Vue, et nous l'utiliserons tout au long de ce guide. Elle fonctionne à la fois du côté navigateur et dans l'environnement Node.js, et fonctionne avec n'importe quel programme de test. Nous effectuerons nos tests dans un environnement Node.js tout au long de ce guide. + +Le plus simple est de commencer par `vue-cli`. Il permettra de mettre en place un projet, ainsi que de configurer Jest, un framework populaire de test, Installez-le en exécutant : + + +```sh +yarn global add @vue/cli +``` + +ou avec npm: + +```sh +npm install -g @vue/cli +``` +Créer un nouveau projet en lançant `vue create [project-name]`. Choisir "Manually select features" et "Unit Testing", et "Jest" pour le lanceur de test. + +Une fois l'installation terminée, `cd` dans le projet et lancez `yarn test:unit`. Si tout s'est bien passé, vous devriez voir : + +``` + PASS tests/unit/HelloWorld.spec.js + HelloWorld.vue + ✓ renders props.msg when passed (26ms) + +Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: 2.074s +``` +Félicitation, vous venez juste de passer votre premier test ! + + +## Ecrire votre premier test + +Nous avons effectué un test qui vient avec le projet. Nous allons nous salir les mains, en écrivant notre propre composant, et un test. Traditionnellement, lorsque l'on fait du TDD, on écrit d'abord le test qui échoue, puis on implémente le code qui permet au test de réussir. Pour l'instant, nous allons d'abord écrire le composant. + +Nous n'avons pas besoin de `src/components/HelloWorld.vue` ou de `tests/unit/HelloWorld.spec.js`, donc nous pouvons les supprimer + + +## Créer le composant `Greeting` + +Créer un fichier `Greetind.vue` dans `src/components`. A l'intérieur de `Greeting.vue`, nous ajoutons ce qui suit : + + +```vue + + + +``` + +## Ecrire le test + +`Greeting` n'a que seul responsabilité - de rendre la valeur de `greeting`. La stratégie sera : + + +1. Rendre de composant avec `mount` +2. Affirmer que le texte du composant contient "Vue and TDD" + +Créer un fichier `Greeting.spec.js` dans le dossier `tests/unit`. A l'intérieur, importer `Greeting.vue`, ainsi que `mount` et ajouter le contour du test : + +``` +import { mount } from '@vue/test-utils' +import Greeting from '@/components/Greeting.vue' + +describe('Greeting.vue', () => { + it('renders a greeting', () => { + + }) +}) +``` + +Il y a différentes syntaxes pour utiliser les TDD, nous utiliserons la syntaxe `describe` et `it` qui est fournie avec Jest. Le terme `describe` décrit en général l'objet du test, dans notre cas `Greeting.vue`. `it` représente lui qu'une partie du test qui doit être rempli. Comme nous ajouterons des fonctionnalités au composant, nous ajouterons d'autres blocks `it`. + +Maintenant vous voulons rendre le composant avec `mount`. La pratique standard est d'assigner le composant à une variable appelé `wrapper`. Nous allons aussi afficher la sortie, pour nous assurer que tout fonctionne correctement : + +```js +const wrapper = mount(Greeting) + +console.log(wrapper.html()) +``` + +## Lancer le test + +Lancer le test en tapant `yarn test:unit`dans votre terminale. Tous les fichiers dans le répertoire `tests` se terminant par `.spec.js` seront automatiquement exécuté. Si tout se passe bien, vous devriez voir : + +``` +PASS tests/unit/Greeting.spec.js +Greeting.vue + ✓ renders a greeting (27ms) + +console.log tests/unit/Greeting.spec.js:7 +
+ Vue and TDD +
+``` + +Nous pouvons voir que le code est correct et le test passe. Le test est passé parce qu'il n'y a pas eu d'échec, ce test ne peut jamais échouer, il n'est donc pas encore très utile. Même si nous changeons `Greeting.vue` et supprimons `greeting`du modèle, il passera quand même. Changeons cela. + + +## Faire des vérifications + +Nous devons faire des vérifications pour être sûr que le composant se comporte correctement. Nous pouvons pour cela utilisez l'API `expect` de Jest. Cela ressemble a ceci : `expect(result).to [matcher] (actual)`. + + +_Les Matchers_ sont des méthodes permettant de comparer des valeurs et des objets. Par exemple : + +```js +expect(1).toBe(1) +``` + +La liste complète des matchers est disponible dans la [documentation de Jest](http://jestjs.io/docs/en/expect). `vue-test-utils` n'inclue aucun matchers - celles que Jest fournit sont plus que suffisantes. Si nous voulons comparer le texte de `Greeting`. Nous pourrions écrire : + +```js +expect(wrapper.html().includes("Vue and TDD")).toBe(true) +``` + +mais `vue-test-utils` a un meilleur moyen pour obtenir le code - `wrapper.text`. Finissons le test : + +```js +import { mount } from '@vue/test-utils' +import Greeting from '@/components/Greeting.vue' + +describe('Greeting.vue', () => { + it('renders a greeting', () => { + const wrapper = mount(Greeting) + + expect(wrapper.text()).toMatch("Vue and TDD") + }) +}) +``` + +Nous n'avons plus besoin du `console.log`, donc nous pouvons le supprimer. Lancer les tests avec `yarn test:unit` et si tout se passe bien vous devriez voir : + +``` +PASS tests/unit/Greeting.spec.js +Greeting.vue + ✓ renders a greeting (15ms) + +Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: 1.477s, estimated 2s +``` +Il a l'air bien. Mais il faut toujours voir le test échouer, pour s'assurer qu'il fonctionne vraiment. Dans la méthode TDD traditionnelle, vous écrivez le test avant la mise en œuvre réelle, puis vous utilisez les erreurs pour guider votre code. Assurons-nous que ce test fonctionne vraiment. Faite cette modification dans `Greeting.vue` : + +```vue + + + +``` + +Et maintenant tester avec `yarn test:unit` : + +``` +FAIL tests/unit/Greeting.spec.js +Greeting.vue + ✕ renders a greeting (24ms) + +● Greeting.vue › renders a greeting + + expect(received).toMatch(expected) + + Expected value to match: + "Vue and TDD" + Received: + "Vue without TDD" + + 6 | const wrapper = mount(Greeting) + 7 | + > 8 | expect(wrapper.text()).toMatch("Vue and TDD") + | ^ + 9 | }) + 10 | }) + 11 | + + at Object. (tests/unit/Greeting.spec.js:8:28) +``` + +Jest nous donne un bon retour. Nous pouvons voir ce qui est attendu et le résultat réel, ainsi que sur quelle ligne le test a échoué. Le test a échoué, comme prévu. Revenez sur `Greeting.vue`et assurez-vous que le test est à nouveau réussi. + +Ensuite nous verrons les deux méthodes que `vue-test-utils` fournit pour rendre les composants : `mount` et `shallowMount`. diff --git a/src/fr/simulating-user-input.md b/src/fr/simulating-user-input.md new file mode 100644 index 00000000..0f0077d7 --- /dev/null +++ b/src/fr/simulating-user-input.md @@ -0,0 +1,278 @@ +:::tip Ce livre est écrit pour Vue.js 2 et Vue Test Utils v1. +Vous trouverez la version Vue.js 3 [ici](/v3/fr). +::: + +## Les Événements déclencheurs + +Une des choses les plus courantes que vos composants Vue feront est d'écouter les inputs de l'utilisateur. `vue-test-utils` et Jest facilitent les tests des inputs. Voyons comment utiliser les `trigrer` et les simulations de Jest pour vérifier le bon fonctionnement de nos composants. + +Vous pouvez trouver le code source de cette page [ici](https://github.com/lmiller1990/vue-testing-handbook/tree/master/demo-app/tests/unit/FormSubmitter.spec.js). + +## La Création d'un composant + +Nous allons créer un simple composant formulaire, ``, qui contient un `` et un `