Menyiapkan API Mocking Dengan Mirage JS Dan Vue.js
Diterbitkan: 2022-03-10Di era SPA dan JAMstack, selalu ada pemisahan perhatian antara API dan pengembangan front-end. Hampir semua proyek JavaScript yang dapat ditemukan di alam liar berinteraksi dengan layanan web atau API dan menggunakannya untuk autentikasi atau mendapatkan data terkait pengguna.
Jadi, setiap kali Anda mengerjakan proyek dan API yang diperlukan masih belum diterapkan oleh tim back-end atau Anda perlu menguji fitur dengan cepat, Anda memiliki beberapa opsi berikut:
- Anda dapat melakukan proxy ke versi yang berjalan secara lokal dari backend aktual Anda yang, dalam banyak kasus sebagai pengembang front-end, tidak akan Anda miliki.
- Anda dapat mengomentari permintaan aktual dan mengganti dengan data tiruan. (Ini tidak apa-apa tetapi tidak terlalu bagus karena Anda perlu membatalkannya untuk mencapai produksi dan Anda mungkin tidak dapat menangani status dan latensi jaringan.)
Apa Itu Mengejek API?
API mocking adalah tiruan atau simulasi dari API yang sebenarnya. Ini sebagian besar dilakukan untuk mencegat permintaan yang seharusnya dibuat ke API backend yang sebenarnya tetapi ejekan ini ada di frontend Anda.
Mengapa Mengejek API Penting
Mengejek API sangat penting dalam banyak hal:
- Itu membuat pengalaman pengembangan front-end yang sangat baik untuk tidak bergantung pada API produksi sebelum membangun fitur.
- Anda dapat membagikan seluruh frontend Anda dan itu akan berfungsi tanpa bergantung pada API backend yang sebenarnya.
Apa itu Mirage JS?
Mirage JS dibuat 5 tahun yang lalu dan cukup banyak digunakan di komunitas Ember sebelum Sam Selikoff secara resmi mengumumkan rilisnya pada 24 Januari 2020 di Twitter.
Mirage JS memecahkan kesulitan untuk menguji API backend tanpa bergantung pada API tersebut. Ini memungkinkan pengalaman pengembangan front-end yang mulus dengan mengejek API produksi.
Mirage JS adalah perpustakaan tiruan API untuk kerangka kerja Vue.js, React, Angular, dan Ember
Apa yang Membuat Mirage JS Pilihan yang Lebih Baik?
Ada opsi lain untuk mengejek API (seperti pencegat Axios, server JSON Typicode, dan sebagainya) tetapi yang menurut saya cukup menarik tentang Mirage adalah bahwa hal itu tidak menghalangi proses pengembangan Anda (seperti yang akan Anda lihat ketika kami mengaturnya dengan Vue sebentar lagi). Hal ini ringan namun kuat.
Muncul dengan baterai yang disertakan di luar kotak yang memungkinkan Anda untuk mereplikasi skenario konsumsi API produksi nyata seperti mensimulasikan jaringan yang lambat dengan opsi waktunya.
Memulai Dengan Mirage JS Dan Vue.js
Jadi sekarang setelah Anda mengetahui apa itu Mirage JS dan mengapa itu penting untuk alur kerja pengembangan front-end Anda, mari kita lihat pengaturannya dengan kerangka kerja web progresif: Vue.js.
Membuat Proyek Vue Green-Field (Instalasi Bersih)
Menggunakan Vue CLI, buat proyek Vue.js baru dengan masuk ke direktori yang Anda inginkan untuk membuat dan menjalankan proyek (di terminal Anda):
vue create miragejs-demo-vue
Perintah di atas akan menyiapkan proyek Vue baru yang sekarang dapat Anda cd
dan jalankan baik yarn serve
atau npm run serve
.
#Menginstal Mirage JS
Sekarang mari kita instal Mirage JS sebagai dependensi pengembangan di proyek Vue.js kita dengan menjalankan perintah berikut:
yarn add -D miragejs
Atau jika Anda menggunakan NPM, jalankan ini:
npm install --save-dev miragejs
Dan itu saja! Mirage JS sekarang terinstal di proyek Vue.js kami.
Mari Mengejek Sesuatu
Dengan Mirage JS terinstal, mari kita lihat bagaimana kita mengonfigurasinya untuk berbicara dengan Vue dan membuat tiruan todos dasar (API yang mengembalikan daftar todos) API.
Tentukan Server Anda
Untuk memulai, kita perlu membuat file server.js di direktori /src
dari proyek Vue.js kita. Setelah itu, tambahkan yang berikut ini:
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 }
Kode Dijelaskan
Pertama, file server.js adalah cara Anda mengatur Mirage JS untuk membuat instance baru dari server tiruannya (palsu) yang akan mencegat semua panggilan API yang Anda buat di aplikasi yang cocok dengan rute yang Anda tentukan.
Sekarang, saya setuju hal di atas mungkin berlebihan pada awalnya, tetapi mari kita lihat lebih dekat apa yang terjadi di sini:
import { Server, Model } from 'miragejs'
Dari potongan kode di atas, kita mengimpor Server
dan Model
dari miragejs
.
-
Server
Ini adalah kelas yang diekspos oleh Mirage untuk membantu kami membuat instance baru dari server Mirage JS untuk "dilayani" sebagai server palsu kami. -
Model
Kelas lain yang diekspos oleh Mirage untuk membantu membuat model (model menentukan struktur entri database Mirage JS) yang didukung oleh ORM Mirage.
export function makeServer({ environment = "development" } = {}) {}
Di atas pada dasarnya mengekspor fungsi yang disebut makeServer
dari src/server.js
. Anda juga dapat mencatat bahwa kami meneruskan parameter lingkungan dan mengatur mode lingkungan Mirage ke development
(Anda akan melihat kami melewati lingkungan pengujian nanti di artikel ini).
Tubuh makeServer
Sekarang kita melakukan beberapa hal di badan makeServer
. Mari lihat:
let server = new Server({})
Kami membuat instance baru dari kelas Server dan memberikannya opsi konfigurasi. Isi opsi konfigurasi membantu mengatur fatamorgana:
{ 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() }) }, }
Pertama kita melewati parameter environment
yang kita inisialisasi dalam definisi fungsi.
models: { todo: Model, },
Opsi berikutnya yang merupakan opsi models
mengambil objek dari model berbeda yang ingin kita tiru oleh Mirage.
Di atas, kita hanya menginginkan model todo yang kita buat dari kelas Model.
seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) },
Opsi selanjutnya adalah metode seed yang mengambil parameter yang disebut server
. Metode seed membantu membuat seed (seed adalah data awal atau entri ke database Mirage) untuk model kami. Dalam kasus kami untuk membuat benih untuk model todo yang kami lakukan:
server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" })
jadi server memiliki metode create yang mengharapkan argumen pertama berupa string yang sesuai dengan nama model, kemudian objek yang akan berisi properti atau atribut dari seed tertentu.
routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) },
akhirnya, kami memiliki metode rute yang mendefinisikan berbagai rute (rute adalah titik akhir API tiruan kami) Mirage JS akan mengejek. Mari kita lihat isi dari metode ini:
this.namespace = "api"
baris ini mengatur namespace untuk semua rute yang berarti rute todo kita sekarang dapat diakses dari /api/todos.
this.get("/todos", schema => { return schema.todos.all() })
Di atas membuat rute get dan handlernya menggunakan metode this.get()
. Metode get()
mengharapkan rute yaitu "/ todos" dan fungsi handler yang mengambil schema
sebagai argumen. Objek skema adalah bagaimana Anda berinteraksi dengan ORM Mirage yang didukung oleh database dalam memori Mirage JS.
Akhirnya:
return schema.todos.all()
Kami mengembalikan daftar semua todos kami, menggunakan objek skema yang dimungkinkan oleh ORM Mirage.
src/main.js
Jadi kita sudah selesai menyiapkan src/server.js
tetapi Vue tidak mengetahuinya (setidaknya belum). Jadi mari kita impor di file main.js kita seperti ini:
import { makeServer } from "./server"
Kemudian kita memanggil fungsi makeServer
seperti ini:
if (process.env.NODE_ENV === "development") { makeServer() }
Kondisi if
di atas adalah penjaga untuk memastikan fatamorgana hanya berjalan dalam pengembangan.
Siapkan Selesai!
Sekarang kita telah menyiapkan Miragejs dengan Vue. Mari kita lihat aksinya. Di file App.vue kami, kami akan menghapus konten dan mengganti dengan cuplikan di bawah ini:
<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>
Jika Anda sudah familiar dengan Vue.js, hal di atas bukanlah hal baru tetapi demi menjadi total, apa yang kami lakukan adalah membuat permintaan API menggunakan fetch
ketika komponen App.vue
kami dibuat, lalu kami meneruskan data yang dikembalikan ke array todos dalam status komponen kami. Setelah itu, kami menggunakan v-for untuk mengulangi array todos dan menampilkan properti konten dari setiap todo.
Dimana Bagian The Mirage JS?
Jika Anda perhatikan, di komponen App.vue kami, kami tidak melakukan sesuatu yang spesifik untuk Mirage, kami hanya membuat panggilan API seperti yang biasa kami lakukan. Fitur Mirage ini sangat bagus untuk DX karena di bawah tenda, Mirage akan mencegat permintaan apa pun yang cocok dengan salah satu rute yang ditentukan di src/server.js saat Anda dalam pengembangan.
Ini cukup berguna karena Anda tidak perlu bekerja untuk beralih ke server produksi aktual saat Anda berada di lingkungan produksi asalkan rutenya cocok dengan titik akhir API produksi Anda.
Jadi restart server Vue dev Anda melalui yarn serve
untuk menguji Mirage JS.
Anda akan melihat daftar dua todos. Satu hal yang menurut Anda cukup menarik adalah bahwa kami tidak perlu menjalankan perintah terminal untuk memulai Mirage karena perintah tersebut menghilangkan overhead tersebut dengan menjalankan sebagai bagian dari aplikasi Vue.js Anda.
Utilitas uji Mirage JS Dan Vue
Jika Anda sudah menggunakan Vue Test-utils di aplikasi Vue Anda, Anda akan merasa senang mengetahui bahwa Mirage dapat dengan mudah bekerja dengannya untuk mengejek permintaan jaringan. Mari kita lihat contoh pengaturan menggunakan aplikasi todos kita.
Kami akan menggunakan Jest untuk pengujian unit kami. Jadi, jika Anda mengikuti, Anda dapat menggunakan Vue CLI untuk menginstal plugin @vue/unit-jest
seperti:
vue add @vue/unit-jest
Di atas akan menginstal dependensi pengembangan @vue/cli-plugin-unit-jest
dan @vue/test-utils
sambil juga membuat direktori tests
dan file jest.config.js . Itu juga akan menambahkan perintah berikut di bagian scripts
package.json kami (cukup rapi):
"test:unit": "vue-cli-service test:unit"
Mari Menguji!
Kami akan memperbarui App.vue kami agar terlihat seperti ini:
<!-- 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>
Tidak ada yang benar-benar epik terjadi dalam cuplikan di atas; kami hanya menyusun untuk memungkinkan pengujian jaringan yang akan kami terapkan dengan pengujian unit kami.
Meskipun Vue CLI telah menambahkan folder /tests
untuk kami, saya merasa itu menjadi pengalaman yang jauh lebih baik ketika pengujian saya ditempatkan dekat dengan komponen yang mereka uji. Jadi buat folder /__tests__
di src/
dan buat file App.spec.js di dalamnya. (Ini juga merupakan pendekatan yang direkomendasikan oleh 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() })
Jadi untuk menyiapkan pengujian unit kami, kami mengimpor metode mount
dari @vue/test-utils
, mengimpor server Miragejs yang kami buat sebelumnya dan akhirnya mengimpor komponen App.vue
.
Selanjutnya, kami menggunakan fungsi siklus hidup beforeEach
untuk memulai server Mirage JS saat melewati lingkungan pengujian. (Ingat, kami menetapkan lingkungan secara default menjadi development
.)
Terakhir, kami mematikan server menggunakan server.shutdown
dalam metode siklus hidup afterEach
.
Tes Kami
Sekarang mari kita menyempurnakan pengujian kita (kita akan mengadopsi bagian quickstart dari dokumen Mirage js. Jadi App.spec.js Anda akhirnya akan terlihat seperti ini:
// 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() })
Catatan : Kami menggunakan pembantu di sini (sebagaimana didefinisikan dalam dokumen Mirage JS). Ini mengembalikan janji yang memungkinkan kita mengetahui kapan elemen yang kita uji sudah ada di DOM.
Sekarang jalankan yarn test:unit
.
Semua tes Anda harus lulus pada saat ini.
Menguji Status Server Berbeda Dengan Mirage JS
Kami dapat mengubah server Mirage JS kami untuk menguji status server yang berbeda. Mari kita lihat bagaimana.
// src/__tests__/App.spec.js import { Response } from "miragejs"
Pertama, kita impor kelas Response
dari Mirage, lalu kita buat skenario pengujian baru seperti ini:
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." ) })
Jalankan tes Anda dan semuanya harus lulus.
Kesimpulan
Artikel ini bertujuan untuk memperkenalkan Anda kepada Mirage JS dan menunjukkan kepada Anda bagaimana hal itu membuat pengalaman pengembangan front-end yang lebih baik. Kami melihat masalah yang dibuat Mirage JS untuk diatasi (membangun front-end siap produksi tanpa API backend yang sebenarnya) dan cara menyiapkannya dengan Vue.js.
Meskipun artikel ini menggores permukaan tentang apa yang dapat dilakukan Mirage JS, saya yakin ini cukup untuk membantu Anda memulai.
- Anda dapat melihat dokumen serta bergabung dengan server perselisihan Mirage JS.
- Repo pendukung untuk artikel ini tersedia di GitHub.
Referensi
- Dokumen Mirage
- Panduan Memulai Mirage Vue