L'ambiente di test

Come spiegato nella sezione Che cos'è il test, i test in JavaScript sono fondamentalmente solo codice che confermiamo che viene eseguito correttamente, ossia senza generare un Error. Tuttavia, uno dei modi in cui questa definizione è una semplificazione eccessiva è che non prende in considerazione dove viene eseguito il codice, ovvero il suo ambiente di test.

L'ambiente di test può essere generalmente costituito da due componenti: l'ambiente di runtime utilizzato per eseguire il test (ad esempio il nodo o il browser) e le API a tua disposizione.

L'ambiente di runtime

I runtime come Node, o strumenti simili come Deno o Bun, hanno lo scopo di supportare il codice JS lato server o generico. I loro ambienti non includono API che potresti aspettarti in un browser, ad esempio la creazione e l'utilizzo degli elementi DOM e HTML, né alcun concetto di componente visivo o di destinazione del rendering (non solo elementi, ma il rendering di questi elementi visivamente con CSS in un'area visibile).

Di conseguenza, questi runtime per uso generico avranno esito negativo se provi, ad esempio, a eseguire il rendering degli elementi React in modo che possano essere testati, perché non sono disponibili oggetti document o window.

Se invece esegui i test all'interno di un browser, le API integrate che puoi aspettarti da questi runtime potrebbero non essere disponibili senza il polyfilling o il lavoro aggiuntivo. Un modo comune è leggere e scrivere file: ma non è possibile import { fs } from 'node:'fs'; all'interno di un browser e leggere un file in questo modo nell'ambito di un test.

Questo problema relativo all'API "web" e al "backend" non rientra nell'ambito del semplice test, perché può essere complicato avere un codebase con parti di server e client, ma si collega all'idea di scrivere codice testabile, che rivedremo in questo corso.

Eseguire test sulla logica di business o algoritmica

Parte del codice non richiede importazioni di nodi o browser per funzionare e, di conseguenza, di testarlo. Ci occuperemo di questo aspetto più avanti in questo corso, ma la struttura del codebase in modo che la sua "logica di business" pura sia separata dal rendering o di un codice specifico per nodo può semplificare i test.

Per un esempio rapido, potresti avere una funzione Nodo che legge e scrive un file dal disco, modificandolo durante il processo. Con il refactoring della funzione in modo da accettare funzioni che eseguono lettura e scrittura da disco, l'hai resa testabile ovunque.

In questo caso, puoi utilizzare qualsiasi ambiente per testare questo codice, in un runtime lato server o nel browser. Nel tuo test, puoi fornire helper per archiviare un file virtuale in memoria o restituire dati segnaposto. Questo tipo di aiuto può essere introdotto in un test, perché non è importante verificare, ad esempio, che fs.writeFileSync funzioni. Concentrati sul tuo codice e su ciò che lo rende unico o rischioso.

Emula API del browser

Molti framework di test, come Vitest, offrono un'opzione per emulare l'ambiente API del browser senza eseguire un browser. Vitest utilizza internamente una libreria chiamata JSDOM. Può essere una buona scelta per testare i componenti semplici in cui l'overhead associato all'utilizzo di un browser è elevato.

Una caratteristica comune di qualsiasi libreria di emulazione è che, sebbene possa emulare un browser, ad esempio DOM, elementi e cookie, non hanno un componente visivo. Questo significa che ti forniranno un modo imperativo di lavorare con gli elementi HTML e altre primitive, ma non potrai eseguire il rendering dell'output in un'immagine o in una schermata né controllare la posizione di un elemento in pixel sulla pagina.

Anche in questo caso, questa scelta può essere adatta per i test di componenti, in cui un componente rappresenta un elemento React, un componente web e così via. Questi tipi di componenti in genere creano e interagiscono con il DOM in un modo relativamente piccolo e un browser emulato può fornire funzionalità sufficienti per confermare che il componente funzioni come previsto. Una prossima sezione include un esempio di test del componente React con Vitest e JSDOM.

L'emulazione di un browser è una pratica consolidata (JSDOM è stato rilasciato nel 2014), ma differirà sempre dall'utilizzo di un browser reale. Queste differenze possono essere evidenti: ad esempio, JSDOM non include un motore di layout, quindi non è possibile controllare le dimensioni di un elemento o testare un gesto complesso come uno scorrimento. Le differenze possono anche essere sottili e sconosciute, motivo per cui è meglio mantenere i test basati su JSDOM concisi, in modo da poter "programmare" il rischio che un comportamento si discosti da quello reale.

Controlla un browser reale

Per testare il tuo codice così come lo vedranno i tuoi utenti, la scelta migliore è l'utilizzo di un browser reale. In pratica, i test dei runtime che supportano il browser avviano e controllano le istanze di un browser reale, anche se viene eseguito il comando "start" all'interno di Node.js.

Controllare un browser come parte di un test significa che si aprirà come farebbe per un utente, consentendo al test di controllarlo caricando URL, codice HTML personalizzato e JS o qualsiasi altro file necessario per eseguire il test. Poi puoi scrivere il codice per agire come utente, ad esempio controllando il mouse o digitando l'input nelle caselle.

Gli strumenti moderni come WebdriverIO o Web Test Runner possono controllare tutti i principali browser e persino eseguire più istanze contemporaneamente. Questi browser possono essere eseguiti accanto all'esecutore del test (ad esempio, sul tuo computer o nell'ambito di un'azione di CI) oppure possono essere esternalizzati a servizi commerciali esterni che li eseguiranno per tuo conto.

Le librerie di test più consolidate (tra cui Vitest e Jest) hanno spesso una modalità browser, ma, poiché la loro origine proviene da Node.js, le loro modalità del browser sono spesso "bloccate" e mancano funzionalità utili. Ad esempio, Vitest non può Simulare le importazioni di moduli nel browser, che è una potente primitiva che usiamo nell'esempio nella pagina successiva.

In pratica

Man mano che i test diventano più complessi, diventa sempre più importante utilizzare un browser reale.

  • Per i test che non utilizzano le funzionalità del DOM o ne utilizzano solo una minima, anche quelle disponibili in Node.js e runtime simili, come fetch o EventTarget, l'ambiente non ha importanza.
  • Per piccoli test dei componenti, JSDOM può essere adatto.
  • I test più grandi, ad esempio i test end-to-end, che possono simulare l'accesso di un utente e l'esecuzione di un'azione principale, hanno senso eseguirli completamente in un browser reale.

Questa sezione è incentrata sulla teoria e presenta diversi punti di vista su dove eseguire i test. In pratica, il codebase utilizza spesso diversi approcci a diversi tipi di test in base alle tue esigenze e a ciò che forniscono gli strumenti di test.

Verifica le tue conoscenze

Quali funzionalità del browser *non* supporta lo strato di emulazione jsdom?

Il motore del layout.
Poiché JSDOM non è uno strumento visivo, non può essere utilizzato per verificare la posizione di un elemento nella pagina, i suoi attributi CSS risolti o qualsiasi altra parte del layout di un sito web.
WebSocket
JSDOM include il polyfill WebSocket, quindi il codice che lo utilizza funzionerà.
requestAnimationFrame
Con il flag "pretendToBe Visual", jsdom richiama il callback "animation" a 60 f/s, anche se in realtà non viene disegnato nulla.