Comportement asynchrone
Vous avez sûrement remarqué que certaines parties de ce guide utilisent await
lors de l'appel de certaines méthodes de wrapper
, telles que trigger
et setValue
. De quoi s'agit-il exactement ?
Vous savez peut-être que Vue se met à jour de manière réactive : lorsque vous changez une valeur, le DOM est automatiquement mis à jour pour refléter la dernière valeur. Vue se met à jour de façon asynchrone. En revanche, un gestionnaire de tests tel que Jest s'exécute de façon synchrone
. Cela peut causer des résultats inattendus dans les tests.
Examinons certaines stratégies pour garantir que Vue met à jour le DOM comme prévu lorsque nous exécutons nos tests.
Un exemple simple - Mettre à jour avec trigger
Réutilisons le composant <Counter>
de la section Tester les Évènements avec une modification ; nous affichons maintenant le count
dans le template
.
const Counter = {
template: `
<p>Compteur: {{ count }}</p>
<button @click="handleClick">Incrémenter</button>
`,
data() {
return {
count: 0,
};
},
methods: {
handleClick() {
this.count += 1;
},
},
};
Écrivons un test pour vérifier que count
s'incrémente :
test('incrémente de 1', () => {
const wrapper = mount(Counter);
wrapper.find('button').trigger('click');
expect(wrapper.html()).toContain('Compteur: 1');
});
Bizarrement, le test échoue ! La raison est simple : bien que count
soit incrémenté, Vue ne mettra pas à jour le DOM jusqu'au prochain tick
du cycle d'événement. Pour cette raison, la vérification (expect()...
) sera appelée avant que Vue ne mette à jour le DOM.
TIP
Si vous voulez en savoir plus sur ce comportement de base de JavaScript, jetez un œil à La boucle d'événement: les microtâches et les macrotâches.
Comment pouvons-nous régler cela ? Vue fournit en réalité un moyen d'attendre jusqu'à ce que le DOM soit mis à jour : nextTick
.
import { nextTick } from 'vue';
test('incrémente de 1', async () => {
const wrapper = mount(Counter);
wrapper.find('button').trigger('click');
await nextTick();
expect(wrapper.html()).toContain('Compteur: 1');
});
Maintenant, le test réussira, car nous veillons à ce que le prochain tick
ait été exécuté et que le DOM ait été mis à jour avant la vérification.
Comme await nextTick()
est courant, Vue Test Utils fournit un raccourci. Les méthodes qui impliquent la mise à jour du DOM, telles que trigger
et setValue
, retournent nextTick
, de sorte que vous pouvez simplement les await
directement :
test('incrémente de 1', async () => {
const wrapper = mount(Counter);
await wrapper.find('button').trigger('click');
expect(wrapper.html()).toContain('Compteur: 1');
});
Résoudre d'autres Comportements Asynchrones
nextTick
est utile pour s'assurer que des changements dans des données réactives sont reflétés dans le DOM avant de poursuivre le test. Cependant, parfois, vous pouvez souhaiter vous assurer que d'autres comportements asynchrones non liés à Vue sont également terminés.
Un exemple courant est une fonction qui retourne une Promise
. Peut-être avez-vous déjà simulé votre client HTTP axios
en utilisant jest.mock
:
jest.spyOn(axios, 'get').mockResolvedValue({ data: 'de la donnée simulée !' });
Dans ce cas, Vue n'a aucune idée si la Promise
est résolue ou non, donc l'appel à nextTick
ne fonctionnera pas - votre vérification peut s'exécuter avant qu'elle ne soit résolue. Pour des scénarios de ce genre, Vue Test Utils propose flushPromises
, qui cause l'exécution immédiate de toutes les Promise
en attente de résolution.
Regardons un exemple :
import { flushPromises } from '@vue/test-utils';
import axios from 'axios';
jest.spyOn(axios, 'get').mockResolvedValue({ data: 'de la donnée simulée !' });
test('utilise une méthode pour simuler la méthode d\'axios et flushPromises', async () => {
// le composant appelle la méthode de `axios` lorsque le composant est créé.
const wrapper = mount(AxiosComponent);
await flushPromises() // la `Promise` de la méthode Axios est résolue immédiatement.
// après cette ligne, la requête axios est résolue avec la donnée simulée.
});
TIP
Si vous souhaitez en savoir plus sur les tests de requêtes sur les composants, assurez-vous de consulter la section Faire des requêtes HTTP.
Tester un setup
asynchrone
Si le composant que vous voulez tester utilise un setup
asynchrone, vous devez monter le composant à l'intérieur d'un composant Suspense
(comme vous le faites lorsque vous l'utilisez dans votre application).
Par exemple, prenons ce composant Async
:
const Async = defineComponent({
async setup() {
// await quelque chose
},
});
… doit être testé comme suit :
test('Composant async', () => {
const TestComponent = defineComponent({
components: { Async },
template: '<Suspense><Async/></Suspense>'
});
const wrapper = mount(TestComponent);
// ...
});
Conclusion
- Vue met à jour le DOM de manière asynchrone ; les tests, au contraire, s'exécutent de manière synchrone.
- Utilisez
await nextTick()
pour vous assurer que le DOM a été mis à jour avant de continuer des tests. - Les fonctions qui peuvent mettre à jour le DOM (comme
trigger
etsetValue
) renvoientnextTick
, il est donc nécessaire de lesawait
. - Utilisez
flushPromises
de Vue Test Utils pour résoudre les promesses non résolues provenant de dépendances non-Vue (telles que les requêtes API). - Utilisez
Suspense
pour tester les composants avec unsetup
asynchrone.