Il testing del software è fondamentale per garantire che le vostre applicazioni funzionino come previsto, soprattutto quando introducete delle modifiche. Individuare e correggere gli errori nelle prime fasi dello sviluppo è fondamentale per mantenere un codice resistente e di alta qualità.
Tra i tanti strumenti e framework disponibili per il testing di JavaScript, Jest è uno dei più popolari. Prodotto da Meta, Jest offre ampie funzionalità di testing per le applicazioni JavaScript e per quelle realizzate con framework JavaScript.
Vediamo insieme il framework Jest, le sue caratteristiche e il modo migliore per integrarlo nel vostro workflow di sviluppo.
Cos’è Jest?
Jest è un framework flessibile e semplice da usare. Oltre alle sue funzioni principali di test JavaScript, offre configurazioni e plugin per supportare il test di applicazioni basate su Babel, webpack, Vite, Parcel o TypeScript.
Jest è stato largamente adottato da chi lavora nello sviluppo e vanta una serie di plugin costruiti e gestiti dalla comunità. Si distingue per la sua facilità d’uso: i test JavaScript non richiedono configurazioni o plugin aggiuntivi. Ma potete anche eseguire test più avanzati, come quelli sui framework JavaScript, utilizzando alcune opzioni di configurazione aggiuntive.
Come configurare Jest per il vostro progetto JavaScript
Vediamo come configurare Jest in un progetto JavaScript esistente.
Prerequisiti
Per seguire questo tutorial, assicuratevi di avere i seguenti requisiti:
- Node.js installato.
- npm (già parte di Node.js) o Yarn installati.
- Il pacchetto Jest npm installato.
Installare il pacchetto Jest
- Se non avete già un progetto da seguire in questo tutorial, usate questo repo come punto di partenza.
Il branch starter-files
vi fornisce una base per costruire l’applicazione mentre seguite il tutorial. Fate riferimento al main
per visualizzare il codice di questo tutorial e fare un controllo incrociato del vostro codice.
- Per installare Jest con npm, andate nella directory del progetto nel vostro terminale ed eseguite il seguente comando:
npm install --save-dev jest
L’opzione --save-dev
indica a npm di installare il pacchetto sotto devDependencies
, che contiene le dipendenze necessarie per lo sviluppo.
Configurare Jest
Anche se Jest funziona generalmente senza alcuna configurazione aggiuntiva, ci sono due modi per espandere la sua potenza: dal file package.json e tramite un file di configurazione di Jest.
Configurare Jest in package.json
Nel file package.json, aggiungete un oggetto chiamato jest
con le proprietà mostrate di seguito:
{
…
"jest": {
"displayName": "Ecommerce",
"globals": {
"PROJECT_NAME": "Ecommerce TD"
},
"bail": 20,
"verbose": true
},
}
Durante il test, Jest cerca questo oggetto e applica queste configurazioni. Potete visualizzare altre opzioni nella pagina delle configurazioni di Jest, ma le proprietà di questo oggetto includono:
displayName
: Jest aggiunge il valore di questa proprietà come etichetta ai risultati del test.globals
: contiene il valore di un oggetto per definire le variabili globali disponibili negli ambienti di test.bail
: per impostazione predefinita, Jest esegue tutti i test e visualizza gli errori nei risultati.bail
indica a Jest di interrompere l’esecuzione dopo un determinato numero di test non riusciti.verbose
: se impostato sutrue
, mostra i report dei singoli test durante la loro esecuzione.
Configurare Jest in un file di configurazione
Potete anche configurare Jest in un file jest.config.js. Jest supporta anche le estensioni .ts, .mjs, .cjs e .json. Quando esegue i test, Jest cerca questi file e applica le impostazioni del file che trova.
Per esempio, prendiamo questo file jest.config.js:
const config = {
displayName: "Ecommerce",
globals: {
"PROJECT_NAME": "Ecommerce TD"
},
bail: 20,
verbose: true
}
module.exports = config;
Il codice esporta un oggetto di configurazione Jest con le stesse proprietà dell’esempio precedente.
Potete anche usare un file personalizzato che contenga un oggetto di configurazione serializzabile JSON e passare il percorso del file all’opzione --config
durante l’esecuzione dei test.
Creare un file di test di base
Dopo aver configurato Jest, create i vostri file di test. Jest esamina i file di test del vostro progetto, li esegue e fornisce i risultati. I file di test di solito seguono un formato simile a [nome].test.js o [nome]-test.js. Questo schema facilita l’identificazione dei file di test sia da parte di Jest che del vostro team.
Prendiamo in esame un file string-format.js con il seguente codice:
function truncate(
str,
count,
withEllipsis = true
) {
if (str.length < = count)
return str
const substring = str.substr(0, count)
if (!withEllipsis)
return substring
return substring + '...'
}
module.exports = { truncate }
La funzione truncate()
tronca le stringhe a una determinata lunghezza con l’opzione di aggiungere un’ellissi.
Scrivere il test
- Create un file di prova chiamato string-format.test.js.
- Per mantenere l’organizzazione dei vostri file, posizionate string-format.test.js nella stessa directory in cui si trova il file string-format.js o in una directory di test specifica. Indipendentemente dalla posizione del file di test all’interno del progetto, Jest lo trova e lo esegue. Con Jest potete testare le vostre applicazioni in vari scenari.
- Scrivete un test di base in string-format.test.js come segue:
const { truncate } = require('./string-format')
test('truncates a string correctly', () = > {
expect(truncate("I am going home", 6)).toBe('I am g...')
})
Il caso di test ha la descrizione truncates a string correctly
. Questo codice usa la funzione expect
fornita da Jest, che verifica se un valore corrisponde al risultato atteso.
Il codice passa truncate("I am going home", 6)
come argomento a expect
. Questo codice testa il valore restituito dalla chiamata a truncate
con gli argomenti "I am going home"
e 6
. La chiamata a expect
restituisce un oggetto expectation, che offre accesso alle corrispondenze di Jest.
Contiene anche il matcher toBe
, che ha "I am g…"
come argomento. Il matcher toBe
verifica l’uguaglianza tra i valori attesi e quelli reali.
Eseguire il test
Per eseguire i vostri test, definite il comando jest
.
- Nel file package.json del vostro progetto, aggiungete questo script
test
:
"scripts": {
"test": "jest"
}
- Ora eseguite
npm run test
,npm test
onpm t
nel vostro terminale. Esegue Jest per il progetto.
Quando eseguite i test, il risultato è questo:
I risultati mostrano una suite di test (il file string-format.test.js), un test eseguito con successo ("truncates a string correctly"
) e il displayName
(Ecommerce
) che avete definito nella configurazione.
- In string-format.js, se aggiungete un punto in più per interrompere il codice ed eseguire il test, questo fallisce:
Questo risultato suggerisce che la funzione truncate
è stata interrotta o che sono stati fatti degli aggiornamenti che richiedono l’aggiornamento dei test.
Come scrivere i test con Jest
Sintassi dei test Jest
La sintassi proprietaria di Jest è semplice da usare. Jest espone al vostro progetto metodi e oggetti globali per la scrittura dei test. Alcuni dei suoi termini fondamentali sono describe
, test
, expect
e matcher.
describe
: questa funzione raggruppa i test correlati in un file.test
: questa funzione esegue il test. È un alias diit
. Contiene le asserzioni per i valori che volete testare.expect
: questa funzione dichiara le asserzioni per i vari valori. Fornisce l’accesso ai matcher per varie forme di asserzioni.- Matcher: vi permettono di asserire un valore in vari modi. Potete asserire l’uguaglianza dei valori, l’uguaglianza booleana e l’uguaglianza contestuale (per esempio se un array contiene il valore).
Per usarli, considerate il seguente esempio:
- Sostituite il test nel file string-format.test.js con il seguente codice:
describe("all string formats work as expected", () = > {
test("truncates a string correctly", () = > {
expect(
truncate("I am going home", 6)
).toBe("I am g...")
})
})
- Eseguite il codice.
Il risultato è il seguente:
La schermata mostra che l’etichetta della funzione describe
crea un blocco. Sebbene describe
sia facoltativo, è utile raggruppare i test in un file con un contesto più ampio.
Organizzare i test in suite di test
In Jest, un caso di test è composto dalla funzione test
, dalla funzione expect
e da un matcher. Un insieme di casi di test correlati è una suite di test. Nell’esempio precedente, string-format.test.js è una suite di test che comprende un caso di test per verificare il file string-format.js.
Supponiamo di avere altri file nel progetto, come file-operations.js, api-logger.js e number-format.js. Potete creare delle suite di test per questi file, come file-operations.test.js, api-logger.test.js e number-format.test.js.
Scrivere semplici asserzioni con Jest Matchers
Abbiamo esplorato un esempio di utilizzo del matcher toBe
. Le asserzioni con altri matcher Jest includono:
toEqual
: per verificare l’uguaglianza “profonda” nelle istanze degli oggetti.toBeTruthy
: per verificare se un valore è vero in un contesto booleano.toBeFalsy
: per verificare se un valore è falso in un contesto booleano.toContain
: per verificare che un array contenga un valore.toThrow
: per verificare che una funzione invocata lanci un errore.stringContaining
: per verificare che una stringa contenga una sottostringa.
Vediamo alcuni esempi di utilizzo di questi matcher.
Per esempio, potreste aspettarvi che una funzione o un codice restituisca un oggetto con proprietà e valori specifici.
- Usate lo snippet di codice qui sotto per testare questa funzionalità. In questo caso, volete verificare che l’oggetto restituito sia uguale all’oggetto previsto.
expect({
name: "Joe",
age: 40
}).toBe({
name: "Joe",
age: 40
})
Questo esempio usa toBe
. Il test fallisce perché questo matcher non controlla l’uguaglianza profonda: controlla il valore, non tutte le proprietà.
- Usate il matcher
toEqual
per verificare l’uguaglianza profonda:
expect({
name: "Joe",
age: 40
}).toEqual({
name: "Joe",
age: 40
})
Questo test viene superato perché entrambi gli oggetti sono “profondamente uguali”, ovvero tutte le loro proprietà sono uguali.
- Provate un altro esempio di matcher che verifica se l’array definito contiene un elemento specifico.
expect(["orange", "pear", "apple"]).toContain("mango")
Questo test fallisce perché toContain
afferma che l’array ["orange", "pear", "apple"]
contiene il valore atteso "mango"
, ma l’array non lo contiene.
- Usate le variabili per lo stesso test del codice sottostante:
const fruits = ["orange", "pear", "apple"];
const expectedFruit = "mango";
expect(fruits).toContain(expectedFruit)
Testare il codice asincrono
Finora abbiamo testato il codice sincrono, cioè espressioni che restituiscono un valore prima che il codice esegua la riga successiva. Potete usare Jest anche per il codice asincrono con async
, await
o Promises.
Per esempio, il file apis.js contiene una funzione per effettuare una richiesta API:
function getTodos() {
return fetch('https://jsonplaceholder.typicode.com/todos/1')
}
La funzione getTodos
invia una richiesta GET
a https://jsonplaceholder.typicode.com/todos/1
.
- Create un file chiamato apis.test.js con il seguente codice per testare la finta API:
const { getTodos } = require('./apis')
test("gets a todo object with the right properties", () = > {
return getTodos()
.then((response) = > {
return response.json()
})
.then((data) = > {
expect(data).toHaveProperty('userId')
expect(data).toHaveProperty('id')
expect(data).toHaveProperty('title')
expect(data).toHaveProperty('completed')
expect(data).toHaveProperty('description')
})
})
Questo caso di test invoca la funzione getTodos
che recupera un oggetto todo
. Quando risolve la Promise, usa il metodo .then
per ottenere il valore risolto.
In questo valore, il codice restituisce response.json()
, che è un’altra Promise che converte la risposta in formato JSON. Un altro metodo .then
ottiene l’oggetto JSON contenente expect
e i matcher. Il codice afferma che l’oggetto JSON include cinque proprietà: userId
, id
, title
, completed
e description
.
- Eseguire i test:
Come mostra lo screenshot, il test per getTodos()
fallisce. Si aspetta la proprietà description
, ma l’API non la restituisce. Grazie a queste informazioni, potete chiedere al team di gestione delle API della vostra azienda di includere questa proprietà se l’applicazione ne ha bisogno o di aggiornare i test per soddisfare la risposta dell’API.
- Rimuovete l’asserzione per la proprietà
description
e rieseguite i test:
Lo screenshot mostra che tutto ha superato il test.
- Ora provate a usare
async/await
invece della tradizionale gestione di Promise:
test("gets a todo object with the right properties", async () = > {
const response = await getTodos()
const data = await response.json()
expect(data).toHaveProperty("userId")
expect(data).toHaveProperty("id")
expect(data).toHaveProperty("title")
expect(data).toHaveProperty("completed")
})
La parola chiave async
si trova ora prima della funzione. Il codice usa await
prima di getTodos()
e await
prima di response.json()
.
Caratteristiche avanzate di Jest
Funzioni e moduli mock
Quando scrivete i test, potreste voler testare un’espressione con dipendenze esterne. In alcuni casi, soprattutto nei test unitari, i test unitari devono essere isolati dagli effetti esterni. In questo caso, potete fare il mock delle vostre funzioni o dei vostri moduli con Jest per controllare meglio i vostri test.
- Per esempio, consideriamo un file functions.js che contiene il seguente codice:
function multipleCalls(count, callback) {
if (count < 0) return;
for (let counter = 1; counter <= count; counter++) {
callback()
}
}
La funzione multipleCalls
viene eseguita in base al valore di count
. Essa dipende dalla funzione di callback, la dipendenza esterna. Il suo scopo è sapere se multipleCalls
esegue correttamente la dipendenza esterna.
- Per simulare la dipendenza esterna e monitorare lo stato della dipendenza nel vostro file di test, functions.test.js, usate questo codice:
const { multipleCalls } = require('./functions')
test("functions are called multiple times correctly", () => {
const mockFunction = jest.fn()
multipleCalls(5, mockFunction)
expect(
mockFunction.mock.calls.length
).toBe(5)
})
Qui, il metodo fn
dell’oggetto jest
crea una funzione mock. Poi, il codice esegue multipleCalls
passando 5
e la funzione mock come argomenti. Quindi, afferma che mockFunction
viene chiamato cinque volte. La proprietà mock
contiene informazioni su come il codice chiama la funzione e sui valori restituiti.
- Quando si esegue il test, questo è il risultato atteso:
Come dimostrato, il codice chiama il sito mockFunction
cinque volte.
Nel codice, la funzione mock imita una dipendenza esterna. Non importa quale sia la dipendenza esterna quando l’applicazione usa multipleCalls
in produzione. Al vostro test unitario non interessa come funziona la dipendenza esterna. Verifica solo che multipleCalls
funzioni come previsto.
- Per simulare i moduli, usate il metodo
mock
e passate un percorso di file, che è il modulo:
const {
truncate,
} = require("./string-format")
jest.mock("./string-format.js")
Questo codice imita tutte le funzioni che string-format.js esporta e tiene traccia della frequenza con cui le chiama. La funzione truncate
del modulo diventa una funzione mock, che fa perdere alla funzione la sua logica originale. Potete scoprire quante volte truncate
viene eseguito nei vostri test nella proprietà truncate.mock.calls.length
.
Se vedete un errore o il vostro codice non funziona, confrontatelo con l’implementazione completa.
Testare i componenti React con Jest e la libreria di test React
Se non avete già un progetto da seguire in questo tutorial, potete usare questo progetto di esempio React come punto di partenza. Il branch starter-files
vi aiuta a iniziare a comporre il codice mentre seguite il tutorial. Usate il main
come riferimento per fare un controllo incrociato tra il vostro codice e il codice completo di questo tutorial.
Potete usare Jest per testare framework JavaScript come React. Quando create progetti React con Create React App, questi supportano la React Testing Library e Jest. Se create un progetto React senza Create React App, installate Jest per testare React con Babel e la libreria di testing React. Se clonate il ramo starter-app
, non dovrete installare le dipendenze o applicare le configurazioni.
- Se state usando il progetto di esempio, usate questo comando per installare le dipendenze necessarie:
npm install --save-dev babel-jest @babel/preset-env @babel/preset-react react-testing-library
Potete anche usare Enzyme al posto di React Testing Library.
- Aggiornate le configurazioni di Babel in babel.config.js o create questo file se non esiste:
module.exports = {
presets: [
'@babel/preset-env',
['@babel/preset-react', {runtime: 'automatic'}],
],
};
- Considerate il file src/SubmitButton.js che ha il seguente codice:
import React, { useState } from 'react'
export default function SubmitButton(props) {
const {id, label, onSubmit} = props
const [isLoading, setisLoading] = useState(false)
const submit = () => {
setisLoading(true)
onSubmit()
}
return
Questo componente SubmitButton
riceve tre prop:
id
: l’identificatore del pulsante.label
: il testo da rendere nel pulsante.onSubmit
: quale funzione attivare quando qualcuno fa clic sul pulsante.
Il codice assegna il prop id
all’attributo data-testid
, che identifica un elemento da testare.
Il componente tiene traccia anche dello stato isLoading
e lo aggiorna a true
quando qualcuno fa clic sul pulsante.
- Create il test per questo componente. Inserite il seguente codice nel file SubmitButton.test.js:
import {fireEvent, render, screen} from "@testing-library/react"
import "@testing-library/jest-dom"
import SubmitButton from "./SubmitButton"
test("SubmitButton becomes disabled after click", () => {
const submitMock = jest.fn()
render(
<SubmitButton
id="submit-details"
label="Submit"
onSubmit={submitMock}
/ >
)
expect(screen.getByTestId("submit-details")).not.toBeDisabled()
fireEvent.submit(screen.getByTestId("submit-details"))
expect(screen.getByTestId("submit-details")).toBeDisabled()
})
Il codice precedente esegue il rendering del componente SubmitButton
e usa il metodo di interrogazione screen.getByTestId
per ottenere il nodo DOM in base all’attributo data-testid
.
Il primo expect
è getByTestId("submit-details")
e usa il modificatore not
e il matcher toBeDisabled
(esposto da react-testing-library
) per affermare che il pulsante non è disabilitato. Usate il modificatore not
con ogni matcher per affermare il contrario del matcher.
Quindi il codice lancia l’evento submit
sul componente e verifica che il pulsante sia disabilitato. Potete trovare altri matcher personalizzati nella documentazione della libreria di test.
- Ora eseguite i test. Se avete clonato il branch
starter-files
, assicuratevi di aver installato tutte le dipendenze del progetto eseguendonpm install
prima di iniziare i test.
Eseguire i report di copertura del codice
Jest offre anche dei report sulla copertura del codice per mostrare la parte del progetto che state testando.
- Passate l’opzione
--coverage
a Jest. Nello script Jest in package.json (nel progetto JavaScript), aggiornate il comando Jest con questa opzione di copertura:
"scripts": {
"test": "jest --coverage"
}
- Eseguite
npm run test
per testare il vostro codice. Otterrete un report come il seguente:
Questo report mostra che Jest ha testato il 100% delle funzioni in SubmitButton.js e string-format.js. Indica inoltre che Jest non ha testato nessuna istruzione e nessuna riga di string-format.js. La copertura dei test mostra che le linee scoperte in string-format.js sono 7 e 12.Alla riga 7, return str
nella funzione truncate
non viene eseguito perché la condizione if (str.length <= count)
restituisce false
.
Alla riga 12, sempre nella funzione truncate
, return substring
non viene eseguito perché la condizione if (!withEllipsis)
ritorna false.
Integrare Jest con il vostro workflow di sviluppo
Vediamo come integrare questi test per migliorare il vostro workflow di sviluppo.
Eseguire i test in modalità Watch
Invece di eseguire manualmente i test, potete eseguirli automaticamente quando modificate il codice usando la modalità di osservazione.
- Per abilitare la modalità di osservazione, aggiornate il vostro script di comando Jest in package.json (nel progetto JavaScript) aggiungendo l’opzione
--watchAll
:
"scripts": {
"test": "jest --coverage --watchAll"
}
- Eseguite
npm run test
. Attivate Jest in modalità watch:
I test vengono eseguiti ogni volta che modificate il progetto. Questo approccio favorisce un feedback continuo durante la creazione dell’applicazione.
Impostare gli hook pre-commit
Negli ambienti Git, gli hook eseguono gli script ogni volta che si verifica un particolare evento (come un pull, un push o un commit). Gli hook di pre-commit definiscono quali script vengono eseguiti per l’evento di pre-commit (che il codice attiva prima di effettuare un commit).
Il commit va a buon fine solo se lo script non lancia un errore.
L’esecuzione di Jest prima del pre-commit assicura che nessuno dei vostri test fallisca prima del commit.
Potete usare diverse librerie per impostare gli hook di git nel vostro progetto, come per esempio ghooks.
- Installate
ghooks
sottodevDependencies
:
npm install ghooks --save-dev
- Aggiungete un oggetto
configs
nel livello superiore del vostro file package.json (nel progetto JavaScript). - Aggiungete un oggetto
ghooks
sottoconfigs
.
- Aggiungete una proprietà con una chiave di
pre-commit
e un valore dijest
.
{
…
"config": {
"ghooks": {
"pre-commit": "jest"
}
},
}
- Eseguite il commit del codice. Il codice attiva l’hook pre-commit, che esegue Jest:
Riepilogo
Ora sapete come integrare Jest nel vostro flusso di sviluppo per eseguirlo automaticamente ogni volta che apportate una modifica. Questo approccio fornisce un feedback continuo che vi permette di correggere rapidamente eventuali problemi del codice prima di rilasciare le modifiche in produzione.
Ospitando la vostra applicazione con Kinsta, potrete beneficiare di un’infrastruttura veloce e sicura, e distribuire i vostri progetti su un’infrastruttura costruita sulla rete Premium Tier di Google Cloud Platform e su macchine C2. Potrete scegliere tra 37 data center e un CDN abilitato HTTP/3 con 260+ PoPs.
Restate al sicuro con la tecnologia dei container isolati, due firewall potenti e una protezione DDoS avanzata alimentata da Cloudflare. Inoltre, potete integrare le app o automatizzare i flussi di lavoro con l’API di Kinsta.
Configurate Jest e consultate le risorse di Kinsta oggi stesso per migliorare le vostre applicazioni JavaScript.
Lascia un commento