Configurazione di API Mocking con Mirage JS e Vue.js
Pubblicato: 2022-03-10Nell'era di SPA e JAMstack, c'è sempre stata una separazione delle preoccupazioni tra le API e lo sviluppo front-end. Quasi tutti i progetti JavaScript che possono essere trovati in natura interagiscono con un servizio Web o un'API e lo utilizzano per le autenticazioni o per ottenere dati relativi all'utente.
Quindi, ogni volta che stai lavorando a un progetto e l'API necessaria non è ancora stata implementata dal team di back-end o devi testare rapidamente una funzionalità, hai alcune delle seguenti opzioni:
- Potresti inviare un proxy a una versione in esecuzione locale del tuo back-end effettivo che, nella maggior parte dei casi come sviluppatore front-end, non avresti.
- Puoi commentare la richiesta effettiva e sostituirla con dati fittizi. (Va bene, ma non così eccezionale in quanto dovresti annullarlo per arrivare alla produzione e potresti non essere in grado di gestire gli stati della rete e la latenza.)
Che cos'è il mocking dell'API?
Il mocking dell'API è un'imitazione o una simulazione di un'API reale. Viene principalmente fatto per intercettare le richieste che dovrebbero essere inviate a un'API di back-end effettiva, ma questa presa in giro esiste sul tuo front-end.
Perché è importante la beffa dell'API
Il mocking dell'API è molto importante in molti modi:
- È un'esperienza di sviluppo front-end molto buona non dipendere dalle API di produzione prima di creare funzionalità.
- Potresti condividere l'intero front-end e funzionerebbe senza dipendere da un'effettiva API di back-end.
Cos'è Mirage JS?
Mirage JS è stato creato 5 anni fa ed è stato praticamente utilizzato nella comunità di Ember prima che Sam Selikoff ne annunciasse ufficialmente il rilascio il 24 gennaio 2020 su Twitter.
Mirage JS risolve il punto dolente per testare le API di back-end senza dipendere da tali API. Consente un'esperienza di sviluppo front-end senza interruzioni prendendo in giro le API di produzione.
Mirage JS è una libreria di simulazione API per i framework Vue.js, React, Angular ed Ember
Cosa rende Mirage JS una scelta migliore?
Ci sono state altre opzioni per il mocking delle API (come gli intercettori Axios, il server JSON di Typicode e così via), ma quello che penso sia piuttosto interessante in Mirage è che non interferisce con il tuo processo di sviluppo (come vedresti quando l'abbiamo configurata con Vue tra un po'). È leggero e tuttavia potente.
Viene fornito con una batteria inclusa pronta all'uso che consente di replicare scenari di consumo API di produzione reale come la simulazione di una rete lenta con la sua opzione di temporizzazione.
Introduzione a Mirage JS e Vue.js
Quindi ora che sai cos'è Mirage JS e perché è importante per il tuo flusso di lavoro di sviluppo front-end, diamo un'occhiata alla configurazione con il framework Web progressivo: Vue.js.
Creazione di un progetto Vue Green-Field (installazione pulita).
Utilizzando Vue CLI, crea un nuovo progetto Vue.js andando nella directory in cui desideri che il progetto venga creato e in esecuzione (nel tuo terminale):
vue create miragejs-demo-vue
Il comando precedente imposterebbe un nuovo progetto Vue in cui ora è possibile eseguire il cd
ed eseguire yarn serve
o npm run serve
.
#Installazione di Mirage JS
Ora installiamo Mirage JS come dipendenza di sviluppo nel nostro progetto Vue.js eseguendo il comando seguente:
yarn add -D miragejs
O se stai usando NPM, esegui questo:
npm install --save-dev miragejs
E questo è tutto! Mirage JS è ora installato nel nostro progetto Vue.js.
Prendiamo in giro qualcosa
Con Mirage JS installato, vediamo come lo configuriamo per parlare con Vue e simulare un'API di base di cose da fare (un'API che restituisce un elenco di cose da fare).
Definisci il tuo server
Per iniziare, dobbiamo creare un file server.js nella directory /src
del nostro progetto Vue.js. Successivamente, aggiungi quanto segue:
import { Server, Model } from 'miragejs' export function makeServer({ environment = "development" } = {}) { let server = new Server({ environment, models: { todo: Model, }, seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) }, routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) }, }) return server }
Codice spiegato
In primo luogo, il file server.js è il modo in cui configuri Mirage JS per creare una nuova istanza del suo server fittizio (falso) che intercetterà tutte le chiamate API che fai nella tua app corrispondenti ai percorsi che definisci.
Ora, sono d'accordo che quanto sopra potrebbe essere travolgente all'inizio, ma diamo un'occhiata più da vicino a cosa sta succedendo qui:
import { Server, Model } from 'miragejs'
Dal frammento di codice sopra, stiamo importando Server
e Model
da miragejs
.
-
Server
Questa è una classe esposta da Mirage per aiutarci a creare un'istanza di una nuova istanza di un server Mirage JS per "servire" come nostro server falso. -
Model
Un'altra classe esposta da Mirage per aiutare nella creazione di modelli (un modello determina la struttura di una voce del database Mirage JS) basata sull'ORM di Mirage.
export function makeServer({ environment = "development" } = {}) {}
Quanto sopra sostanzialmente esporta una funzione chiamata makeServer
da src/server.js
. Potresti anche notare che stiamo passando un parametro di ambiente e impostando la modalità ambiente di Mirage su development
(ci vedresti passare l'ambiente di test più avanti in questo articolo).
Il corpo di makeServer
Ora stiamo facendo un paio di cose nel corpo di makeServer
. Diamo un'occhiata:
let server = new Server({})
Stiamo istanziando una nuova istanza della classe Server e passandole un'opzione di configurazione. Il contenuto delle opzioni di configurazione aiuta a configurare mirage:
{ environment, models: { todo: Model, }, seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) }, routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) }, }
Per prima cosa stiamo passando il parametro di environment
che abbiamo inizializzato nella definizione della funzione.
models: { todo: Model, },
L'opzione successiva, che è l'opzione models
, prende un oggetto dei diversi modelli che vogliamo che Mirage prenda in giro.
In quanto sopra, vogliamo semplicemente un modello todo che stiamo istanziando dalla classe Model.
seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) },
L'opzione successiva è il metodo seed che accetta un parametro chiamato server
. Il metodo dei semi aiuta a creare semi (i semi sono dati iniziali o una voce nel database di Mirage) per i nostri modelli. Nel nostro caso per creare i semi per il modello todo facciamo:
server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" })
quindi il server ha un metodo create che prevede come primo argomento una stringa che corrisponde al nome del modello, quindi un oggetto che conterrà le proprietà o gli attributi di un particolare seme.
routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) },
infine, abbiamo il metodo delle rotte che definisce le varie rotte (le rotte sono i nostri endpoint API fittizi) Mirage JS prenderà in giro. Diamo un'occhiata al corpo del metodo:
this.namespace = "api"
questa riga imposta lo spazio dei nomi per tutti i percorsi, il che significa che ora è possibile accedere al nostro percorso da fare da /api/todos.
this.get("/todos", schema => { return schema.todos.all() })
Quanto sopra crea un percorso get ed è un gestore che utilizza il metodo this.get()
. Il metodo get()
si aspetta il percorso, ad esempio "/todos" e una funzione di gestione che accetta schema
come argomento. L'oggetto schema è il modo in cui interagisci con l'ORM di Mirage che è alimentato dal database in memoria Mirage JS.
Finalmente:
return schema.todos.all()
Stiamo restituendo un elenco di tutti i nostri impegni, utilizzando l'oggetto schema reso possibile dall'ORM di Mirage.
src/main.js
Quindi abbiamo finito di configurare src/server.js
ma Vue non lo sa (almeno non ancora). Quindi importiamolo nel nostro file main.js in questo modo:
import { makeServer } from "./server"
Quindi chiamiamo la funzione makeServer
in questo modo:
if (process.env.NODE_ENV === "development") { makeServer() }
Quanto sopra, if
condizionale, è una protezione per assicurarsi che il miraggio venga eseguito solo in fase di sviluppo.
Configurazione completata!
Ora abbiamo configurato Miragejs con Vue. Vediamolo in azione. Nel nostro file App.vue , cancelleremo il contenuto e lo sostituiremo con lo snippet seguente:
<template> <ul> <li v-for="todo in todos" v-bind:key="todo.id">{{ todo.content }}</li> </ul> </template> <script> export default { name: 'app', data() { return { todos: [] } }, created() { fetch("/api/todos") .then(res => res.json()) .then(json => { this.todos = json.todos }) } } </script>
Se hai familiarità con Vue.js, quanto sopra non sarebbe una novità, ma per il gusto di essere totale, quello che stiamo facendo è fare una richiesta API usando fetch
quando viene creato il nostro componente App.vue
, quindi passiamo i dati restituiti all'array todos nel nostro stato componente. Successivamente, utilizzeremo un v-for per iterare l'array todos e visualizzare la proprietà del contenuto di ogni todo.
Dov'è la parte di Mirage JS?
Se noti, nel nostro componente App.vue, non abbiamo fatto nulla di specifico per Mirage, stiamo solo effettuando una chiamata API come faremmo normalmente. Questa caratteristica di Mirage è davvero eccezionale per DX perché sotto il cofano, Mirage intercetterebbe tutte le richieste che corrispondono a qualsiasi percorso definito in src/server.js mentre sei in fase di sviluppo.
Questo è piuttosto utile perché non sarebbe necessario alcun lavoro da parte tua per passare a un server di produzione reale quando ti trovi in un ambiente di produzione, a condizione che i percorsi corrispondano agli endpoint dell'API di produzione.
Quindi riavvia il tuo server di sviluppo Vue tramite il yarn serve
per testare Mirage JS.
Dovresti vedere un elenco di due cose da fare. Una cosa che potresti trovare piuttosto interessante è che non abbiamo bisogno di eseguire un comando da terminale per avviare Mirage perché rimuove quel sovraccarico eseguendo come parte della tua applicazione Vue.js.
Mirage JS e Vue test-utils
Se stai già utilizzando Vue Test-utils nella tua applicazione Vue, troveresti eccitante sapere che Mirage può facilmente lavorare con esso per deridere le richieste di rete. Vediamo un esempio impostato utilizzando la nostra applicazione todos.
Useremmo Jest per i nostri unit test. Quindi, se stai seguendo, potresti praticamente usare Vue CLI per installare il plugin @vue/unit-jest
questo modo:
vue add @vue/unit-jest
Quanto sopra installerà le dipendenze di sviluppo @vue/cli-plugin-unit-jest
e @vue/test-utils
creando anche una directory tests
e un file jest.config.js . Aggiungerà anche il seguente comando nella nostra sezione degli scripts
package.json (piuttosto pulito):
"test:unit": "vue-cli-service test:unit"
Testiamo!
Aggiorneremmo il nostro App.vue in modo che assomigli a questo:
<!-- src/App.vue --> <template> <div v-if="serverError" data-test> {{ serverError }} </div> <div v-else-if="todos.length === 0" data-test> No todos! </div> <div v-else> <ul> <li v-for="todo in todos" v-bind:key="todo.id" :data-test > {{ todo.content }} </li> </ul> </div> </template> <script> export default { name: "app", data() { return { todos: [], serverError: null, } }, created() { fetch("/api/todos") .then(res => res.json()) .then(json => { if (json.error) { this.serverError = json.error } else { this.todos = json.todos } }) }, } </script>
Niente di veramente epico sta succedendo nel frammento di cui sopra; ci stiamo solo strutturando per consentire il test di rete che implementeremo con il nostro unit test.
Sebbene Vue CLI abbia già aggiunto una cartella /tests
per noi, trovo che sia un'esperienza molto migliore quando i miei test sono posizionati vicino ai componenti che stanno testando. Quindi crea una cartella /__tests__
in src/
e crea un file App.spec.js al suo interno. (Questo è anche l'approccio consigliato da Jest.)
// src/__tests__/App.spec.js import { mount } from "@vue/test-utils" import { makeServer } from "../server" import App from "../App.vue" let server beforeEach(() => { server = makeServer({ environment: "test" }) }) afterEach(() => { server.shutdown() })
Quindi, per impostare il nostro unit test, stiamo importando il metodo di mount
da @vue/test-utils
, importando il server Miragejs che abbiamo creato in precedenza e infine importando il componente App.vue
.
Successivamente, utilizziamo la funzione del ciclo di vita beforeEach
per avviare il server Mirage JS durante il passaggio nell'ambiente di test. (Ricorda, impostiamo per impostazione predefinita l'ambiente come development
.)
Infine, stiamo spegnendo il server utilizzando server.shutdown
nel metodo afterEach
lifecycle.
I nostri test
Ora approfondiamo il nostro test (adotteremmo la sezione di avvio rapido dei documenti Mirage js. Quindi il tuo App.spec.js sarebbe finalmente simile a questo:
// src/__tests__/App.spec.js import { mount } from "@vue/test-utils" import { makeServer } from "./server" import App from "./App.vue" let server beforeEach(() => { server = makeServer({ environment: "test" }) }) it("shows the todos from our server", async () => { server.create("todo", { id: 1, content: "Learn Mirage JS" }) server.create("todo", { id: 2, content: "Integrate with Vue.js" }) const wrapper = mount(App) // let's wait for our vue component to finish loading data // we know it's done when the data-testid enters the dom. await waitFor(wrapper, '[data-test]') await waitFor(wrapper, '[data-test]') expect(wrapper.find('[data-test]').text()).toBe("Learn Mirage JS") expect(wrapper.find('[data-test]').text()).toBe("Integrate with Vue.js") }) it("shows a message if there are no todo", async () => { // Don't create any todos const wrapper = mount(App) await waitFor(wrapper, '[data-test]') expect(wrapper.find('[data-test]').text()).toBe("No todos!") }) // This helper method returns a promise that resolves // once the selector enters the wrapper's dom. const waitFor = function(wrapper, selector) { return new Promise(resolve => { const timer = setInterval(() => { const todoEl = wrapper.findAll(selector) if (todoEl.length > 0) { clearInterval(timer) resolve() } }, 100) }) } afterEach(() => { server.shutdown() })
Nota : qui stiamo usando un helper (come definito nei documenti Mirage JS). Restituisce una promessa che ci consente di sapere quando gli elementi che stiamo testando sono già nel DOM.
Ora esegui yarn test:unit
.
Tutti i tuoi test dovrebbero passare a questo punto.
Testare diversi stati del server con Mirage JS
Potremmo modificare il nostro server Mirage JS per testare diversi stati del server. Vediamo come.
// src/__tests__/App.spec.js import { Response } from "miragejs"
Innanzitutto, importiamo la classe Response
da Mirage, quindi creiamo un nuovo scenario di test in questo modo:
it("handles error responses from the server", async () => { // Override Mirage's route handler for /todos, just for this test server.get("/todos", () => { return new Response( 500, {}, { error: "The database is taking a break.", } ) }) const wrapper = mount(App) await waitFor(wrapper, '[data-test]') expect(wrapper.find('[data-test]').text()).toBe( "The database is taking a break." ) })
Esegui il test e tutto dovrebbe passare.
Conclusione
Questo articolo intendeva presentarti Mirage JS e mostrarti come migliora l'esperienza di sviluppo front-end. Abbiamo visto il problema che Mirage JS ha creato per risolvere (costruzione di front-end pronto per la produzione senza alcuna API di back-end effettiva) e come configurarlo con Vue.js.
Sebbene questo articolo abbia graffiato la superficie di ciò che Mirage JS può fare, credo che sia sufficiente per iniziare.
- Potresti esaminare i documenti e unirti al server discord Mirage JS.
- Il repository di supporto per questo articolo è disponibile su GitHub.
Riferimenti
- I documenti del miraggio
- Avvio rapido Mirage Vue