Immergiamoci in Cypress per i test end-to-end

Pubblicato: 2022-03-10
Riepilogo rapido ↬ Il test end-to-end è un argomento doloroso per te? In questo articolo, Ramona Schwering spiega come gestire i test end-to-end con Cypress e renderlo non così noioso e costoso per te stesso, ma piuttosto divertente.

Oggi è difficile immaginare lo sviluppo di software senza test automatizzati. Una buona varietà di diverse procedure di prova garantirà un elevato livello di qualità. Come base per i test, possiamo utilizzare una serie di test unitari. Inoltre, nel mezzo della piramide, per così dire, ci sono i test di integrazione. I test end-to-end sono in cima e coprono i casi d'uso più critici. Questo terzo tipo di test sarà al centro di questo articolo.

Tuttavia, i test end-to-end presentano alcune insidie ​​che sono motivo di preoccupazione:

  • I test end-to-end sono lenti e, quindi, rappresentano un ostacolo significativo in ogni strategia di integrazione continua e distribuzione continua (CI/CD). Non solo, ma immagina di finire un'attività, una funzionalità o qualsiasi altra implementazione: aspettare che il test venga eseguito può prosciugare la pazienza di tutti.
  • Tali test end-to-end sono difficili da mantenere, soggetti a errori e costosi in ogni modo a causa dello sforzo di debug. Vari fattori possono causare questo. Il tuo test dovrebbe sembrare un assistente, mai un ostacolo.
  • L'incubo più grande per gli sviluppatori è un test traballante, che è un test che viene eseguito allo stesso modo ma porta a risultati diversi. È come un "Heisenbug", che si verifica solo se non si misura l'applicazione in fase di test, cioè se non la si guarda.
Heisenbug
Gli Heisenfail sono reali e simili agli Heisenbugs. (Grande anteprima)

Ma non preoccuparti: non devi soccombere a queste insidie. Diamo un'occhiata a come prevenirne molti . Tuttavia, non mi limiterò a promettere la luna e non a consegnare. In questa guida, scriveremo insieme alcuni test, che ho reso pubblici per te in un repository GitHub. In questo modo, spero di mostrarti che i test finali possono essere divertenti! Iniziamo.

Cosa sono i test end-to-end?

Quando si parla di test end-to-end (o E2E), mi piace definirlo "basato sul flusso di lavoro". La frase riassume bene i test end-to-end: simula i flussi di lavoro degli utenti effettivi e dovrebbe includere il maggior numero possibile di aree funzionali e parti dello stack tecnologico utilizzato nell'applicazione. Alla fine, il computer finge di essere un cliente e cerca di comportarsi come un utente reale. Questi test sono i migliori per applicare uno stress costante all'intero sistema dell'applicazione e, quindi, sono un'ottima misura per garantire la qualità quando è presente l'intero stack dell'applicazione.

Robot
I test end-to-end vengono eseguiti da un computer che simula un utente reale. (Grande anteprima)

Ricordiamo cosa vogliamo ottenere con tutto questo. Sappiamo che il test front-end è un insieme di pratiche per testare l'interfaccia utente di un'applicazione Web, inclusa la sua funzionalità. Ha senso: con queste misure, possiamo assicurarci che la nostra applicazione funzioni correttamente e che nessuna modifica futura romperà il nostro codice. Per raggiungere questo obiettivo in modo efficiente, potresti chiederti cosa e quanto devi testare.

Questa è una domanda valida. Potresti trovare una possibile risposta in una metafora: la piramide dell'automazione dei test, introdotta per la prima volta da Mike Cohn e ulteriormente specificata da Martin Fowler, mostra come rendere efficienti i test . Troviamo unit test veloci ed economici al livello piramidale più basso e test dell'interfaccia utente costosi e dispendiosi in termini di tempo (test end-to-end) nella parte superiore.

Piramide di prova
La piramide del test di automazione. (Grande anteprima)

Spiegare questo e i suoi vantaggi e svantaggi sarebbe sufficiente per il proprio articolo. Vorrei concentrarmi su un livello. I test end-to-end, in particolare, possono apportare miglioramenti significativi in ​​termini di qualità se definiti in modo efficiente per priorità. In tal modo, possiamo sottoporre costantemente il nostro sistema a stress e garantire che le funzioni principali della nostra applicazione funzionino correttamente.

Il mio viaggio verso il cipresso

Quando ho iniziato a imparare a scrivere test end-to-end, ho usato Mink, una libreria PHP, oltre a Behat, un framework BDD (Comportament-driven Development) orientato allo scenario. Ho iniziato a usare il selenio, con tutti i suoi vantaggi e svantaggi. Poiché il mio team ha iniziato a lavorare molto con Vue.js, siamo passati a un framework di test basato su JavaScript per garantire un'integrazione e una compatibilità impeccabili. La nostra scelta all'epoca era Nightwatch.js, quindi ho creato la nostra nuova suite di test da zero.

Durante questo periodo, ci siamo spesso imbattuti in problemi di compatibilità . Potresti chiamarlo inferno delle dipendenze , per non parlare di tutte le limitazioni che abbiamo visto con Selenium e successivamente con WebDriver.

  • Nel nostro team, non siamo stati in grado di definire la versione Chrome del nostro CI. Quindi, se sono stati rilasciati aggiornamenti a Chrome, Nightwatch.js non è stato abbastanza veloce da essere compatibile, causando molti errori nelle nostre pipeline di test.
  • Il numero di cause lato test di test traballanti ha iniziato ad aumentare, poiché le possibilità di attesa di Nightwatch.js non corrispondevano in modo ottimale al nostro prodotto.

Quindi, abbiamo pensato di creare di nuovo la nostra suite di test. Dopo aver visitato una non conferenza, ho scoperto Cypress.

Cypress è un framework di test all-in-one che non utilizza Selenium o WebDriver. Lo strumento utilizza Node.js per avviare un browser sotto un controllo speciale. I test in questo framework vengono eseguiti a livello di browser, non solo di controllo remoto. Ciò offre diversi vantaggi.

In breve, ecco i motivi per cui ho scelto questo framework:

  • Eccellente capacità di debug
    Il test runner di Cypress può tornare a qualsiasi stato dell'applicazione tramite snapshot. Quindi, possiamo vedere direttamente un errore e tutti i passaggi precedenti. Inoltre, c'è pieno accesso agli strumenti per sviluppatori di Chrome (DevTools) e i clic vengono registrati completamente.
  • Modi migliori per attendere le azioni nel test o nell'interfaccia utente o nelle risposte dell'API
    Cypress porta l'attesa implicita, quindi non sono necessari controlli appropriati. Puoi anche fare in modo che il test attenda animazioni e risposte API.
  • I test sono scritti in JavaScript
    Ciò attenua la curva di apprendimento per scrivere i test. Il test runner di Cypress è open source, quindi si adatta alla nostra strategia di prodotto.

Tuttavia, questo articolo è una guida, quindi fermiamoci con queste informazioni generali e iniziamo.

Iniziare

Installa e avvia Cypress

Cominciamo da zero. Nei miei discorsi su Cypress, di solito inizio creando una nuova directory tramite mkdir , quindi installo immediatamente Cypress. Il modo più semplice per installare è mostrato in questo disegno:

Cypress utilizza Node.js
Cypress utilizza Node.js (anteprima grande)

Un piccolo suggerimento: se non vuoi usare npm, puoi installare Cypress tramite Yarn:

 yarn add cypress --dev

Un'alternativa è il download diretto, utilizzando le cartelle ZIP fornite da Cypress. Questo è tutto! Una volta completata l'installazione, sei pronto per iniziare.

Esistono due modi per iniziare a eseguire i test Cypress. Il primo è avviare Cypress nella console ed eseguire i test senza testa:

 ./node_modules/.bin/cypress run

Il secondo modo consiste nell'utilizzare una delle caratteristiche di Cypress, che è il suo test runner integrato. Il test runner è un'interfaccia utente per l'esecuzione dei test. Per avviarlo, puoi usare un comando simile:

 ./node_modules/.bin/cypress open

Questo comando aprirà il corridore del test. Quando apri Cypress per la prima volta, vedrai questa interfaccia:

Corridore di prova di Cypress
Il corridore di Cypress a prima vista. (Grande anteprima)

Cypress fornisce alcuni test di esempio prescritti per mostrare le sue caratteristiche e darti alcuni punti di partenza: questo è il motivo dei test disponibili. Ignoriamo quelli per ora, perché vogliamo scriverne presto uno. Tuttavia, tieni presente questa area "Test di integrazione", perché spiegherà gran parte della magia che accadrà in seguito.

Prima impressione della struttura di Cypress

Ora è il momento di aprire il nostro progetto appena creato nell'ambiente di sviluppo integrato (IDE) preferito. Se accedi a questa cartella, vedrai la seguente struttura di test:

 smashing-example └── cypress └── fixtures └── integration └── plugins └── support └── cypress.json

Esaminiamo queste cartelle:

  • fixtures
    Qui è dove troverai dati di test fissi, che non hanno alcuna relazione con le altre entità. Quindi, nessun ID viene memorizzato qui, che può cambiare in base allo stato locale.
  • integration
    Qui troverai i test effettivi.
  • plugins
    Qui puoi estendere Cypress, sia con i plug-in Cypress esistenti che con i tuoi.
  • support
    Qui puoi estendere Cypress stesso. I tuoi comandi e aiutanti si trovano qui.
  • cypress.json
    Modifica le configurazioni qui, anche per l'ambiente.

Va bene, penso che ora possiamo orientarci intorno a Cypress, che si tratti del test runner o del codice sorgente. Ma come iniziamo? Cosa vogliamo testare?

Scegli un caso di prova

Un tipico test end-to-end può diventare complesso, in particolare se prevede molti passaggi. Ci vorrebbe molto tempo per l'esecuzione manuale. A causa di questa complessità, i test E2E possono essere difficili da automatizzare e lenti da eseguire. Di conseguenza, dobbiamo decidere con attenzione quali casi automatizzare.

A mio parere, il termine "basato sul flusso di lavoro" è fondamentale : selezioniamo casi di test in base alle tipiche storie degli utenti. Tuttavia, a causa dei tempi di esecuzione, non è consigliabile coprire ogni singolo flusso di lavoro disponibile. Pertanto, abbiamo bisogno di un modo per dare priorità ai nostri casi di test.

Nella mia squadra, avevamo diversi criteri per il nostro progetto. Il test case dovrebbe:

  • coprire i flussi di lavoro più generali e più utilizzati di una funzionalità, come le operazioni CRUD (il termine "percorso felice" descrive abbastanza bene questi flussi di lavoro);
  • utilizzare l'analisi del rischio, coprendo i flussi di lavoro con i test E2E più vulnerabili (ovvero dove gli errori causerebbero il maggior danno);
  • evitare la doppia copertura;
  • non deve essere necessariamente utilizzato se i test unitari sono più appropriati (usa un test E2E per testare la risposta del tuo software a un errore, non l'errore stesso).

La seconda cosa più importante da tenere a mente è testare solo il flusso di lavoro che si desidera testare esplicitamente. Tutti gli altri passaggi necessari per far funzionare il test devono essere eseguiti con operazioni API al di fuori del test, per evitare di testarli. In questo modo, garantirai tempi di esecuzione del test minimi e otterrai un risultato chiaro del tuo test case se fallisce. Pensa a questo flusso di lavoro come farebbe un utente finale: concentrati sull'utilizzo della funzionalità piuttosto che sull'implementazione tecnica .

Esempio:

Se desideri testare il processo di pagamento in un negozio online, non eseguire tutti gli altri passaggi, come la creazione dei prodotti e delle categorie, anche se ti serviranno per elaborare il pagamento. Utilizzare, ad esempio, un'API o un dump del database per fare queste cose e configurare il test solo per il checkout.

Esempio: trovare i miei articoli su Smashing Magazine

Voglio scrivere un test per questo sito Web, Smashing Magazine. Non posso garantire che questo test sarà aggiornato per sempre, ma speriamo che duri. Ad ogni modo, sarai in grado di trovare questo esempio in un repository GitHub.

Creazione del nostro primo test sui cipressi

Nella cartella di integration , inizieremo creando un nuovo file. Chiamiamolo find-author.spec.js . Il suffisso .spec sta per "specifica". In termini di test, si riferisce ai dettagli tecnici di una determinata funzione o applicazione che l'applicazione deve soddisfare.

Per trasformare questo file JavaScript vuoto nella casa di un test, inizieremo dando alla suite di test la sua struttura. Useremo il metodo chiamato describe . describe() , o context() , viene utilizzato per contenere e organizzare i test. In altre parole, questo metodo funge da cornice per i nostri test. Pertanto, il nostro file di test sarà simile a questo:

 // find-author.spec.js describe('Find authors at smashing', () => { //... });

Il passaggio successivo consiste nel creare il test vero e proprio. Useremo il metodo it . it() , o specify() , viene utilizzato per rappresentare il test effettivo. Come puoi vedere, possiamo acquisire più test in un file, il che consente alcune eccellenti opzioni di strutturazione.

 // find-author.spec.js describe('Find authors at smashing', () => { it('Find the author Ramona Schwering', () => { cy.log('This is our brand-new test'); }); });

Piccolo suggerimento : se hai familiarità con Mocha, potresti aver notato alcune somiglianze. Cypress è costruito su Mocha, quindi la sintassi è la stessa.

Va bene, procediamo. Se eseguiamo il nostro test nel test runner di Cypress, noteremo che Cypress aprirà un browser per eseguire il test. Questo browser è visibile nello screenshot qui sotto:

Esecuzione del nostro primo test
Il nostro primo test, eseguito nel test runner di Cypress. (Grande anteprima)

Congratulazioni! Abbiamo scritto il nostro primo test! Certo, non fa molto. Dobbiamo continuare. Riempiamo di vita la nostra prova.

Riempi il test di vita

Qual è la prima cosa da fare quando si testa un sito web? Giusto, dobbiamo aprire il sito web. Possiamo farlo usando un comando Cypress. Qual è il comando, ti starai chiedendo?

Lavorare con i comandi

Ci sono principalmente due tipi di istruzioni utilizzate in un test E2E. Il primo tipo di istruzione, i comandi, rappresenta i singoli passaggi del test. Nel contesto di Cypress, i comandi sono tutto ciò che Cypress fa per interagire con il tuo sito web. Questa interazione potrebbe essere qualsiasi cosa: un clic, lo scorrimento del sito Web o persino la ricerca di un elemento. Di conseguenza, i comandi saranno una delle cose importanti con cui riempiremo il nostro test.

Quindi, il nostro primo comando sarà quello per navigare sul sito Web: smashingmagazine.com . Questo comando è chiamato visit .

Usandolo, il nostro test sarà simile a questo:

 // find-author.spec.js describe('Find authors at smashing', () => { it('Find the author Ramona Schwering', () => { cy.visit('https://www.smashingmagazine.com/'); }); });

C'è un comando che uso spesso e lo farai anche tu. Si chiama get :

 cy.get('selector');

Questo comando restituisce un elemento in base al suo selettore, simile a $(…) di jQuery. Quindi, useresti questo comando per trovare le parti con cui interagire. Di solito, lo useresti per avviare una catena di comandi. Ma aspetta, cosa si intende per catena di comandi?

Come accennato all'inizio di questo articolo, tutti i test e tutto il resto sono scritti in JavaScript. Puoi mettere i comandi nei test (cioè le istruzioni) in una catena (concatenata, in altre parole). Ciò significa che i comandi possono passare un oggetto (o un valore di ritorno) di un comando al comando successivo, come sappiamo da molti framework di test.

Va bene, inizieremo una catena di comandi con il comando get . Per trovare un elemento con get , dobbiamo prima trovare il suo selettore. Trovare un selettore univoco è essenziale, perché altrimenti Cypress restituirebbe tutti gli elementi corrispondenti; quindi, tienilo a mente ed evitalo se non è intenzionale.

Interagire con gli elementi

Cypress stesso ha una funzione per aiutarti a trovare i selettori degli elementi con cui vuoi lavorare. Questa funzione è chiamata Selector Playground e ti aiuta a scoprire selettori univoci di un componente o a vedere tutti gli elementi corrispondenti per un selettore o una stringa di testo. Quindi, questa funzione può aiutarti molto in questo compito. Per abilitarlo, fai semplicemente clic sull'icona del mirino nell'intestazione dell'interfaccia utente del test, quindi passa il mouse sopra l'elemento desiderato:

Usando il selettore parco giochi
Utilizzo di Selector Playground per identificare i selettori univoci. (Grande anteprima)

Come si vede nello screenshot qui sopra, un suggerimento mostrerà il selettore al passaggio del mouse o in questa piccola barra sotto l'icona del mirino, che è apparsa quando è stato fatto clic sull'elemento. In questa barra, puoi anche vedere quanti elementi corrisponderebbero a un determinato selettore, garantendone l'unicità nel nostro caso.

A volte, quei selettori generati automaticamente potrebbero non essere quelli che si desidera utilizzare (ad esempio se sono lunghi o difficili da leggere o se non soddisfano gli altri criteri). Il selettore generato di seguito è difficile da capire e troppo lungo, a mio modesto parere:

Non un selezionatore ideale
Questo selettore potrebbe non essere l'ideale da usare. (Grande anteprima)

In questo caso, tornerei ai DevTools del browser per trovare i miei selettori unici. Potresti avere familiarità con questi strumenti; nel mio caso, scelgo spesso Chrome per questo scopo. Tuttavia, altri browser supportati potrebbero fornire funzionalità simili. Il processo sembra simile a Selector Playground, tranne per il fatto che stiamo usando le funzionalità di DevTools nella scheda "Elemento".

Trovare i selettori tramite gli strumenti per sviluppatori
Utilizzo degli strumenti di sviluppo del browser per trovare selettori univoci. (Grande anteprima)

Per garantire che un selettore sia univoco, ti consiglio di cercarlo nella visualizzazione del codice di DevTools. Se trovi un solo risultato, puoi essere certo che è unico.

Lo sapevi che ci sono molti diversi tipi di selettore ? A seconda della varietà, i test possono apparire e persino comportarsi in modo piuttosto diverso. Alcune varietà sono più adatte per i test end-to-end rispetto ad altre. Se vuoi sapere quali selettori utilizzare per mantenere i tuoi test stabili e puliti, posso indicarti uno dei miei articoli che tratta questo problema. Gli stessi sviluppatori di Cypress forniscono alcune indicazioni su questo argomento nelle loro migliori pratiche.

Il nostro test come sequenza di comandi

OK, torniamo al nostro test. In esso, vogliamo visualizzare il nostro flusso di lavoro:

"Io, come utente, cercherò l'articolo dell'autore e navigherò sul sito Web dell'autore attraverso l'area di riferimento in uno dei suoi articoli."

Riprodurremo i passaggi che un utente eseguirebbe utilizzando i comandi. Incollerò sotto il test finito con i commenti, che spiegheranno i passaggi:

 // find-author.spec.js it('Find the author Ramona Schwering', () => { // Open the website cy.visit('https://www.smashingmagazine.com'); // Enter author's name in search field cy.get('#js-search-input').type('Ramona Schwering'); // Navigate to author's article cy.get('h2 > a').first().click(); // Open the author's page cy.get('.author-post__author-title').click(); });

Questo esempio riguarda il flusso di lavoro che vogliamo testare. Cypress eseguirà questo test. Allora, è il momento di dire "Congratulazioni"? Abbiamo finalmente finito di scrivere il nostro primo test?

Bene, per favore dai un'occhiata più da vicino . Cypress lo eseguirà, ma farà solo ciò che il test gli dice, che è quello che hai scritto. Se lo esegui nel test runner, puoi vedere se è passato, ma non nel caso in cui l'hai eseguito senza testa. Con questo test, sappiamo solo se Cypress è stato in grado di eseguire correttamente i nostri comandi, non se siamo finiti sul sito Web dell'autore. Quindi, dobbiamo insegnare il nostro test per determinarlo.

Lavorare con le asserzioni

Il secondo tipo di istruzione si occupa delle descrizioni dello stato desiderato dell'interfaccia utente, ovvero se qualcosa dovrebbe esistere, essere visibile o non essere più visibile. Le affermazioni in Cypress si basano sulle affermazioni Chai e Sinon-Chai, che è evidente nella sintassi.

Ricorda che vogliamo controllare se siamo sulla pagina del profilo dell'autore, la mia in questo esempio. Quindi, dobbiamo aggiungere un'affermazione esattamente per questo:

 // find-author.spec.js it('Find the author Ramona Schwering', () => { // Open the website cy.visit('https://www.smashingmagazine.com'); // Enter author's name in search field cy.get('#js-search-input').type('Ramona Schwering'); // Navigate to author's article cy.get('h2 > a').first().click(); // Open the author's page cy.get('.author-post__author-title').click(); // Check if we're on the author's site cy.contains('.author__title', 'Ramona Schwering').should('be.visible'); });

Va bene, ora abbiamo scritto un test che ha valore. Quindi sì, congratulazioni per aver scritto il tuo primo test... anche se non è ancora perfetto.

Facciamo il nostro test carino

Anche se fossimo riusciti a scrivere un primo test significativo e avessimo appreso il concetto di base nel processo, non lo unirei ancora se fosse proposto in una richiesta pull. Restano un paio di cose da fare per farlo brillare.

Prenditi il ​​tuo tempo

Cypress ha un'opzione di ripetizione incorporata in quasi tutti i comandi, quindi non devi aspettare per vedere se, ad esempio, esiste già un elemento. Tuttavia, questo cerca solo di vedere se esiste un elemento nel DOM, non di più. Cypress non è in grado di prevedere tutto ciò che fa la tua applicazione, quindi potrebbero esserci delle irregolarità se ti affidi esclusivamente a questo.

Tempo nei test end-to-end
Il tempo è un aspetto importante nei test end-to-end. (Grande anteprima)

Cosa farebbe un utente se volesse vedere un sito Web che si sta ancora caricando? Molto probabilmente aspetterebbero che alcune parti del sito Web diventino visibili (quindi caricate) e quindi interagirebbero con esse. Nel nostro test, vogliamo imitare esattamente questo: vogliamo attendere i cambiamenti nell'interfaccia utente prima di iniziare a interagire . Nella maggior parte dei casi, limiteremmo questo comportamento agli elementi di cui abbiamo bisogno, usando così asserzioni su quegli elementi.

Come puoi vedere, dobbiamo far attendere il nostro test in diverse occasioni. Tuttavia, anche aspettare troppe volte non va bene. Come regola pratica, suggerirei di utilizzare un'asserzione per verificare se l'elemento con cui interagire è stato caricato completamente, come primo passaggio per determinare se il sito Web in fase di test è stato caricato.

Diamo un'occhiata a una tale parte del nostro test come esempio. Ho aggiunto un'affermazione per assicurarmi che la nostra pagina sia completamente caricata :

 // find-author-assertions.spec.js // Open website cy.visit('https://www.smashingmagazine.com'); // Ensure site is fully loaded cy.get('.headline-content').should('be.visible'); // Enter author's name in the search field cy.get('#js-search-input').type('Ramona Schwering');

Continua ad aggiungere asserzioni in questo modo a tutti i casi in cui il nostro sito Web avrà tempi di caricamento o diversi elementi che devono essere visualizzati di nuovo. Per il file di test completo, guarda il test corrispondente nel repository GitHub.

Per evitare di cadere nella trappola dei test traballanti, vorrei darti un ultimo suggerimento: non utilizzare mai tempi di attesa fissi, come cy.wait(500) o simili.

Le risposte API sono i tuoi amici

C'è in particolare una possibilità di attesa ordinata che amo sfruttare nei miei test. In Cypress è possibile lavorare con le funzionalità di rete: un altro modo utile di attendere nell'applicazione consiste nell'utilizzare queste funzionalità per gestire le richieste di rete . In questo modo, puoi fare in modo che il test attenda una risposta API riuscita.

Se ricordiamo il nostro flusso di lavoro come esempio, un passaggio potrebbe sfruttare al meglio una possibilità di attesa API. Sto pensando alla ricerca. Una user story corrispondente potrebbe essere la seguente:

"Io, come sviluppatore, voglio assicurarmi che i nostri risultati di ricerca siano completamente caricati in modo che nessun articolo dei risultati precedenti possa fuorviare il nostro test."

Applichiamolo al nostro test. Prima di tutto, dobbiamo definire il percorso che vogliamo aspettare in seguito. Possiamo usare il comando di intercept per questo. Cercherei la richiesta, portando i dati di cui ho bisogno: i risultati della ricerca in questo caso.

Per mantenere questo esempio semplice, userò un carattere jolly per l'URL. Successivamente, userò un alias in modo che Cypress possa lavorare con questo percorso in seguito.

 // find-author-hooks.spec.js // Set the route to work with it('Find the author Ramona Schwering', () => { // Route to wait for later cy.intercept({ url: '*/indexes/smashingmagazine/*', method: 'POST' }).as('search'); // With this alias Cypress will find the request again //...

In Cypress, tutti i percorsi definiti vengono visualizzati all'inizio del test. Quindi, vorrei inserire anche quei comandi di intercept all'inizio del mio test.

Percorso API nel test runner di Cypress
Il percorso API verrà visualizzato all'inizio del nostro test. (Grande anteprima)

Ora, possiamo usare questo alias di route nelle asserzioni. Il modo più snello per farlo sarebbe con il comando wait di Cypress, direttamente con l'alias menzionato prima. Tuttavia, l'utilizzo di questo comando da solo porterebbe ad attendere la risposta indipendentemente dal suo esito . Anche codici di errore come 400 o 500 conterebbero come superati, mentre la tua applicazione molto probabilmente si interromperebbe. Quindi consiglierei di aggiungere un'altra affermazione come questa:

 // find-author-hooks.spec.js // Later: Assertion of the search request's status code cy.wait('@search') .its('response.statusCode').should('equal', 200);
Asserzione sulla risposta dell'API
Asserzione sulla risposta dell'API, come si vede nel test runner di Cypress. (Grande anteprima)

In questo modo possiamo attendere con precisione i dati del software, le modifiche e così via, senza perdere tempo o incorrere in problemi se l'applicazione è fortemente stressata. Ancora una volta, puoi trovare il file di esempio completo nel mio repository GitHub.

Configurazione di Cipresso

Ho omesso un piccolo dettaglio. Se dai un'occhiata più da vicino all'esempio di test completo, differisce leggermente da quelli che abbiamo usato qui in questa guida.

 // Cypress describe('Find author at smashing', () => { beforeEach(() => { // Open website cy.visit('https://www.smashingmagazine.com'); }); //...

Uso solo una barra per aprire il sito Web di Smashing Magazine. Come funziona? Bene, usando questo comando in questo modo baseUrl dei nostri test. baseUrl è un valore di configurazione che può essere utilizzato come prefisso per l'URL del comando cy.visit() o cy.request() . Tra gli altri valori, possiamo definire questo valore nel file cypress.json . Per il nostro test, imposteremo baseUrl in questo modo:

 // cypress.json { "baseUrl": "https://www.smashingmagazine.com" }

Menzione d'Onore: Ganci

C'è ancora un argomento che voglio menzionare, anche se il nostro test di esempio non è adatto per usarlo. Come è comune in altri framework di test, possiamo definire cosa succede prima e dopo i nostri test tramite i cosiddetti hook del ciclo di vita. Più precisamente, esistono per eseguire codice prima o dopo uno o tutti i test:

 // Cypress describe('Hooks', function() { before(() => { // Runs once before all tests }); after(() => { // Runs once after all tests }); beforeEach(() => { // Runs before each test }); afterEach(() => { // Runs after each test }); });

Vogliamo riempire il nostro file di test con più di un test, quindi dovremmo cercare i passaggi comuni che vogliamo eseguire prima o dopo di essi. La nostra prima riga è un esempio calzante, essendo il comando visit . Supponendo di voler aprire questo sito Web prima di ciascuno di questi test, un hook beforeEach nel nostro esempio sarebbe simile a questo:

 // Cypress describe('Find author at smashing', () => { beforeEach(() => { // Open website cy.visit('https://www.smashingmagazine.com'); }); //... 
prima di ogni gancio
Il beforeEach hook viene visualizzato nel registro del corridore del test. (Grande anteprima)

Lo uso spesso nel mio lavoro quotidiano per garantire, ad esempio, che la mia applicazione venga ripristinata allo stato predefinito prima del test , isolando così il test da altri test. ( Non fare mai affidamento sui test precedenti! ) Esegui i test in isolamento l'uno dall'altro per mantenere il controllo sullo stato dell'applicazione.

Ogni test dovrebbe essere in grado di essere eseguito da solo, indipendentemente da altri test. Questo è fondamentale per garantire risultati di test validi . Per i dettagli su questo, vedere la sezione "Dati che condividevamo" in uno dei miei articoli recenti. Per ora, fai riferimento all'esempio completo su GitHub se vuoi vedere l'intero test.

Conclusione

A mio avviso, i test end-to-end sono una componente essenziale della CI, mantenendo alta la qualità delle applicazioni e allo stesso tempo alleviando il lavoro dei tester. Cypress è il mio strumento preferito per eseguire il debug di test end-to-end in modo rapido, stabile ed efficiente e per eseguirli parallelamente a qualsiasi richiesta pull come parte di CI. La curva di apprendimento è delicata se hai già familiarità con JavaScript.

Spero di averti potuto guidare un po' e di averti dato uno spunto per scrivere i test Cypress e alcuni consigli pratici per iniziare. Naturalmente, tutti gli esempi di codice sono disponibili nel repository GitHub, quindi sentiti libero di dare un'occhiata.

Naturalmente, questo è solo un punto di partenza; ci sono molte altre cose da imparare e discutere riguardo ai test Cypress: ti lascio con alcuni suggerimenti su cosa imparare dopo. Con questo in mente, buon test!

Risorse

  • Esempio di smashing originale, Ramona Schwering
    Repository GitHub per l'esempio in questo articolo.
  • Documentazione sui cipressi
  • “Ricette”, Cipresso
    Una selezione di esempi, ricette e portate.
  • "Impara a programmare con JavaScript: Cypress" (lezione), CodeLikeThis
  • Migliori pratiche sulla scrittura di test end-to-end”, Shopware Docs