Configurarea API Mocking cu Mirage JS și Vue.js

Publicat: 2022-03-10
Rezumat rapid ↬ Acest articol prezintă Mirage JS, o bibliotecă de batjocură API care vă permite să construiți, să testați și să partajați o aplicație JavaScript completă, funcțională, fără a fi nevoie să vă bazați pe niciun API sau servicii backend. De asemenea, veți învăța cum să configurați Mirage JS cu framework-ul front-end progresiv, Vue.js.

În era SPA și JAMstack, a existat întotdeauna o separare a preocupărilor între API-uri și dezvoltarea front-end. Aproape toate proiectele JavaScript care pot fi găsite în sălbăticie interacționează cu un serviciu web sau API și fie îl folosesc pentru autentificări, fie pentru a obține date legate de utilizator.

Deci, ori de câte ori lucrați la un proiect și API-ul necesar încă nu a fost implementat de echipa de back-end sau trebuie să testați rapid o funcție, aveți câteva dintre următoarele opțiuni:

  • Ai putea să proxy la o versiune care rulează local a backend-ului tău real pe care, în cele mai multe cazuri, în calitate de dezvoltator front-end, nu ai avea-o.
  • Puteți comenta cererea reală și puteți înlocui cu date simulate. (Este în regulă, dar nu atât de grozav, deoarece ar trebui să anulați asta pentru a ajunge la producție și este posibil să nu puteți face față stărilor și latenței rețelei.)

Ce este API Mocking?

Mocking-ul API este o imitație sau o simulare a unui API real. Se face în mare parte pentru a intercepta cererile care ar trebui să fie făcute către un API backend real, dar această batjocură există pe front-end.

De ce este importantă batjocorirea API

Batjocorirea API este foarte importantă în multe feluri:

  1. Face ca o experiență de dezvoltare front-end foarte bună să nu depindă de API-urile de producție înainte de a construi funcții.
  2. Ai putea partaja întregul tău front-end și ar funcționa fără a depinde de un API backend real.
Mai multe după săritură! Continuați să citiți mai jos ↓

Ce este Mirage JS?

Mirage JS a fost creat acum 5 ani și a fost folosit destul de mult în comunitatea Ember înainte ca Sam Selikoff să-și anunțe oficial lansarea pe 24 ianuarie 2020 pe Twitter.

Mirage JS rezolvă problema pentru testarea API-urilor backend fără a depinde de acele API. Permite o experiență de dezvoltare front-end fără întreruperi, batjocorind API-urile de producție.

Mirage JS este o bibliotecă batjocoritoare API pentru cadrele Vue.js, React, Angular și Ember

Ce face ca Mirage JS să fie o alegere mai bună?

Au existat și alte opțiuni pentru batjocorirea API (cum ar fi interceptoarele Axios, serverul JSON de la Typicode și așa mai departe), dar ceea ce cred că este destul de interesant despre Mirage este că nu vă împiedică procesul de dezvoltare (cum ați vedea când l-am configurat cu Vue într-un pic). Este ușor și totuși puternic.

Vine cu o baterie inclusă din cutie, care vă permite să reproduceți scenarii reale de consum API de producție, cum ar fi simularea unei rețele lente cu opțiunea de sincronizare.

Noțiuni introductive cu Mirage JS și Vue.js

Deci, acum că știți ce este Mirage JS și de ce este important pentru fluxul dvs. de lucru de dezvoltare front-end, să ne uităm la configurarea acestuia cu cadrul web progresiv: Vue.js.

Crearea unui proiect Vue cu câmp verde (instalare curată).

Folosind Vue CLI, creați un nou proiect Vue.js accesând directorul în care doriți să fie creat și rulat proiectul (în terminalul dvs.):

 vue create miragejs-demo-vue

Comanda de mai sus ar configura un nou proiect Vue pe care acum îl puteți cd și rula fie yarn serve fie npm run serve .

#Instalarea Mirage JS

Acum să instalăm Mirage JS ca dependență de dezvoltare în proiectul nostru Vue.js , rulând următoarea comandă:

 yarn add -D miragejs

Sau dacă utilizați NPM, rulați acest lucru:

 npm install --save-dev miragejs

Si asta e! Mirage JS este acum instalat în proiectul nostru Vue.js.

Să ne batjocorim ceva

Cu Mirage JS instalat, să vedem cum îl configuram pentru a vorbi cu Vue și a bate joc de un API de bază todos (un API care returnează o listă de todos).

Definiți-vă serverul

Pentru a începe, trebuie să creăm un fișier server.js în directorul /src al proiectului nostru Vue.js. După aceea, adăugați următoarele:

 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 }

Cod explicat

În primul rând, fișierul server.js este modul în care configurați Mirage JS pentru a crea o nouă instanță a serverului său simulat (fals), care va intercepta toate apelurile API pe care le faceți în aplicația dvs., care se potrivesc cu rutele pe care le definiți.

Acum, sunt de acord că cele de mai sus ar putea fi copleșitoare la început, dar haideți să aruncăm o privire mai atentă la ceea ce se întâmplă aici:

 import { Server, Model } from 'miragejs'

Din fragmentul de cod de mai sus, importăm Server și Model din miragejs .

  • Server
    Aceasta este o clasă expusă de Mirage pentru a ne ajuta să instanțiem o nouă instanță a unui server Mirage JS pentru a „servi” ca server fals.
  • Model
    O altă clasă expusă de Mirage pentru a ajuta la crearea modelelor (un model determină structura unei intrări de bază de date Mirage JS) alimentată de ORM-ul Mirage.
 export function makeServer({ environment = "development" } = {}) {}

Cele de mai sus exportă practic o funcție numită makeServer din src/server.js . De asemenea, puteți observa că trecem un parametru de mediu și setăm modul de mediu al lui Mirage la development (ne-ați vedea trecând mediul de testare mai târziu în acest articol).

Corpul makeServer

Acum facem câteva lucruri în corpul makeServer . Hai să aruncăm o privire:

 let server = new Server({})

Instanțiem o nouă instanță a clasei Server și îi transmitem o opțiune de configurare. Conținutul opțiunilor de configurare ajută la configurarea 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() }) }, }

În primul rând, trecem parametrul de environment pe care l-am inițializat în definiția funcției.

 models: { todo: Model, },

Următoarea opțiune, care este opțiunea models , are un obiect din diferitele modele pe care vrem să le bată joc de Mirage.

În cele de mai sus, vrem pur și simplu un model todo pe care îl instanțiem din clasa Model.

 seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) },

Următoarea opțiune este metoda seeds care preia un parametru numit server . Metoda semințelor ajută la crearea de semințe (semințele sunt date inițiale sau o intrare în baza de date Mirage) pentru modelele noastre. În cazul nostru, pentru a crea semințele pentru modelul todo facem:

 server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" })

deci serverul are o metodă create care așteaptă ca prim argument un șir care corespunde numelui modelului, apoi un obiect care va conține proprietățile sau atributele unei anumite semințe.

 routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) },

în cele din urmă, avem metoda rutelor care definește diferitele rute (rutele sunt punctele finale ale API-ului nostru simulat) Mirage JS va bate joc. Să ne uităm la corpul metodei:

 this.namespace = "api"

această linie setează spațiul de nume pentru toate rutele, ceea ce înseamnă că ruta noastră todo poate fi acum accesată din /api/todos.

 this.get("/todos", schema => { return schema.todos.all() })

Cele de mai sus creează o rută get și este un handler folosind metoda this.get() . Metoda get() așteaptă ruta, adică „/todos” și o funcție de gestionare care ia schema ca argument. Obiectul schema este modul în care interacționați cu ORM-ul Mirage, care este alimentat de baza de date în memorie Mirage JS.

In cele din urma:

 return schema.todos.all()

Vom returna o listă cu toate toate, folosind obiectul schema făcut posibil de ORM-ul Mirage.

src/main.js

Deci am terminat de configurat src/server.js , dar Vue nu știe despre asta (cel puțin nu încă). Deci, să-l importăm în fișierul nostru main.js astfel:

 import { makeServer } from "./server"

Apoi numim funcția makeServer astfel:

 if (process.env.NODE_ENV === "development") { makeServer() }

Cele de mai sus, if sunt condiționate, sunt de pază pentru a vă asigura că mirage rulează doar în dezvoltare.

Configurare completă!

Acum am configurat Miragejs cu Vue. Să-l vedem în acțiune. În fișierul nostru App.vue , vom șterge conținutul și vom înlocui cu fragmentul de mai jos:

 <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>

Dacă sunteți familiarizat cu Vue.js, cele de mai sus nu ar fi nimic nou, dar pentru a fi total, ceea ce facem este să facem o solicitare API folosind fetch atunci când este creată componenta App.vue , apoi transmitem datele returnate. la matricea todos în starea noastră de componentă. Apoi, folosim un v-for pentru a repeta matricea todos și afișăm proprietatea de conținut a fiecărui todo.

Unde este partea Mirage JS?

Dacă observați, în componenta noastră App.vue, nu am făcut nimic specific pentru Mirage, facem doar un apel API așa cum am face în mod normal. Această caracteristică a Mirage este cu adevărat grozavă pentru cauza DX sub capotă, Mirage ar intercepta orice cereri care se potrivesc cu oricare dintre rutele definite în src/server.js în timp ce sunteți în dezvoltare.

Acest lucru este destul de util, deoarece nu ar fi nevoie de muncă din partea dvs. pentru a trece la un server de producție real atunci când vă aflați într-un mediu de producție, cu condiția ca rutele să corespundă punctelor finale ale API-ului de producție.

Așa că reporniți serverul dvs. de dezvoltare Vue prin yarn serve pentru a testa Mirage JS.

Ar trebui să vedeți o listă cu două toate. Un lucru pe care l-ați găsi destul de interesant este că nu a fost nevoie să rulăm o comandă de terminal pentru a porni Mirage, deoarece elimină această suprasarcină rulând ca parte a aplicației dvs. Vue.js.

Mirage JS și Vue-test-utils

Dacă utilizați deja Vue Test-utils în aplicația dvs. Vue, v-ar fi interesant să aflați că Mirage poate lucra cu ușurință cu el pentru a bate joc de solicitările de rețea. Să vedem un exemplu configurat folosind aplicația noastră todos.

Am folosi Jest pentru testarea unitară. Deci, dacă urmați, ați putea utiliza aproape CLI Vue pentru a instala pluginul @vue/unit-jest astfel:

 vue add @vue/unit-jest

Cele de mai sus vor instala dependențele de dezvoltare @vue/cli-plugin-unit-jest și @vue/test-utils , creând, de asemenea, un director de tests și un fișier jest.config.js . De asemenea, va adăuga următoarea comandă în secțiunea noastră de scripts package.json (destul de îngrijită):

 "test:unit": "vue-cli-service test:unit"

Să testăm!

Ne-am actualiza App.vue astfel încât să arate astfel:

 <!-- 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>

Nimic cu adevărat epic nu se întâmplă în fragmentul de mai sus; doar structurăm pentru a permite testarea rețelei pe care le-am implementa cu testul nostru unitar.

Deși Vue CLI a adăugat deja un folder /tests pentru noi, consider că este o experiență mult mai bună atunci când testele mele sunt plasate aproape de componentele pe care le testează. Deci creați un folder /__tests__ în src/ și creați un fișier App.spec.js în interiorul acestuia. (Aceasta este și abordarea recomandată de 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() })

Deci, pentru a configura testarea unitară, importăm metoda de mount din @vue/test-utils , importăm serverul Miragejs pe care l-am creat mai devreme și în final importăm componenta App.vue .

În continuare, folosim funcția ciclului de viață beforeEach pentru a porni serverul Mirage JS în timp ce trecem în mediul de testare. (Nu uitați, am setat în mod implicit mediul pentru development .)

În cele din urmă, închidem serverul folosind server.shutdown în metoda ciclului de viață afterEach .

Testele noastre

Acum să dezvăluim testul nostru (am adopta secțiunea de pornire rapidă a documentelor Mirage js. Deci, App.spec.js ar arăta în sfârșit astfel:

 // 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() })

Notă : folosim un ajutor aici (așa cum este definit în documentele Mirage JS). Returnează o promisiune care ne permite să știm când elementele pe care le testăm sunt deja în DOM.

Acum rulați yarn test:unit .

Toate testele dvs. ar trebui să treacă în acest moment.

Testarea stării diferite a serverului cu Mirage JS

Am putea modifica serverul nostru Mirage JS pentru a testa diferite stări ale serverului. Să vedem cum.

 // src/__tests__/App.spec.js import { Response } from "miragejs"

În primul rând, importăm clasa de Response din Mirage, apoi creăm un nou scenariu de testare astfel:

 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." ) })

Rulați testul și totul ar trebui să treacă.

Concluzie

Acest articol a avut ca scop să vă prezinte Mirage JS și să vă arate cum face pentru o experiență de dezvoltare front-end mai bună. Am văzut problema creată de Mirage JS pentru a o soluționa (crearea unui front-end pregătit pentru producție fără vreun API backend real) și cum să o configuram cu Vue.js.

Deși acest articol a zgâriat suprafața a ceea ce poate face Mirage JS, cred că este suficient pentru a începe.

  • Puteți parcurge documentele, precum și să vă alăturați serverului Mirage JS Discord.
  • Repo de sprijin pentru acest articol este disponibil pe GitHub.

Referințe

  • The Mirage Docs
  • Pornire rapidă Mirage Vue