Настройка имитации API с помощью Mirage JS и Vue.js

Опубликовано: 2022-03-10
Краткое резюме ↬ В этой статье рассказывается о Mirage JS, библиотеке имитации API, которая позволяет создавать, тестировать и совместно использовать законченное работающее приложение JavaScript, не полагаясь на какой-либо серверный API или службы. Вы также узнаете, как настроить Mirage JS с прогрессивной интерфейсной средой Vue.js.

В эпоху SPA и JAMstack всегда существовало разделение между API и фронтенд-разработкой. Почти все проекты JavaScript, которые можно обнаружить в дикой природе, взаимодействуют с веб-службой или API и используют их либо для аутентификации, либо для получения данных, связанных с пользователем.

Итак, когда вы работаете над проектом, а необходимый API еще не реализован бэкэнд-командой или вам нужно быстро протестировать функцию, у вас есть некоторые из следующих вариантов:

  • Вы можете проксировать локально работающую версию вашего фактического бэкенда, чего в большинстве случаев у вас как у фронтенд-разработчика не было бы.
  • Вы можете закомментировать фактический запрос и заменить его фиктивными данными. (Это нормально, но не так здорово, поскольку вам нужно будет отменить это, чтобы перейти к работе, и вы, возможно, не сможете справиться с состояниями сети и задержкой.)

Что такое API-мокинг?

Мокирование API — это имитация или симуляция реального API. В основном это делается для перехвата запросов, которые должны быть отправлены к реальному API-интерфейсу бэкэнда, но эти насмешки существуют в вашем интерфейсе.

Почему API-мокинг важен

Имитация API очень важна во многих отношениях:

  1. Это дает очень хороший опыт разработки интерфейса, чтобы не зависеть от производственных API перед созданием функций.
  2. Вы можете поделиться своим внешним интерфейсом, и он будет работать независимо от фактического внутреннего API.
Еще после прыжка! Продолжить чтение ниже ↓

Что такое Мираж JS?

Mirage JS был создан 5 лет назад и в значительной степени использовался в сообществе Ember до того, как Сэм Селикофф официально объявил о его выпуске 24 января 2020 года в Twitter.

Mirage JS решает проблему тестирования серверных API, не завися от этих API. Это позволяет беспроблемно работать с интерфейсом, имитируя производственные API.

Mirage JS — это библиотека для имитации API для фреймворков Vue.js, React, Angular и Ember.

Что делает Mirage JS лучшим выбором?

Были и другие варианты имитации API (такие как перехватчики Axios, JSON-сервер Typicode и т. д.), но что мне кажется довольно интересным в Mirage, так это то, что он не мешает вашему процессу разработки (как вы видите когда мы немного настроим его с помощью Vue). Он легкий и при этом мощный.

Он поставляется с батареей, которая входит в комплект поставки, что позволяет воспроизводить реальные сценарии использования API-интерфейса, такие как имитация медленной сети с ее параметром синхронизации.

Начало работы с Mirage JS и Vue.js

Итак, теперь, когда вы знаете, что такое Mirage JS и почему он важен для вашего рабочего процесса разработки интерфейса, давайте рассмотрим его настройку с помощью прогрессивной веб-инфраструктуры: Vue.js.

Создание проекта Vue Green-Field (чистая установка)

Используя Vue CLI, создайте новый проект Vue.js , перейдя в каталог, в котором вы хотите, чтобы проект был создан и запущен (в вашем терминале):

 vue create miragejs-demo-vue

Приведенная выше команда настроит новый проект Vue, в который вы теперь можете перейти и запустить либо cd yarn serve , либо npm run serve .

#Установка Mirage JS

Теперь давайте установим Mirage JS в качестве зависимости разработки в нашем проекте Vue.js , выполнив следующую команду:

 yarn add -D miragejs

Или, если вы используете NPM, запустите это:

 npm install --save-dev miragejs

Вот и все! Mirage JS теперь установлен в нашем проекте Vue.js.

Давайте смоделируем что-нибудь

Установив Mirage JS, давайте посмотрим, как мы настроим его для взаимодействия с Vue и смоделируем базовый API-интерфейс todos (API, который возвращает список todos).

Определите свой сервер

Для начала нам нужно создать файл server.js в каталоге /src нашего проекта Vue.js. После этого добавьте следующее:

 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 }

Объяснение кода

Во-первых, файл server.js — это то, как вы настраиваете Mirage JS для создания нового экземпляра своего фиктивного (поддельного) сервера, который будет перехватывать все вызовы API, которые вы делаете в своем приложении, соответствующие определенным вами маршрутам.

Теперь я согласен, что вышеизложенное может показаться ошеломляющим поначалу, но давайте подробнее рассмотрим, что здесь происходит:

 import { Server, Model } from 'miragejs'

Из приведенного выше фрагмента кода мы импортируем Server и Model из miragejs .

  • Server
    Это класс, предоставляемый Mirage, который помогает нам создать экземпляр нового экземпляра сервера Mirage JS, который будет «служить» нашим поддельным сервером.
  • Model
    Еще один класс, предоставляемый Mirage для помощи в создании моделей (модель определяет структуру записи базы данных Mirage JS) на основе ORM Mirage.
 export function makeServer({ environment = "development" } = {}) {}

Вышеупомянутое в основном экспортирует функцию makeServer из src/server.js . Вы также можете заметить, что мы передаем параметр среды и устанавливаем режим среды Mirage в режим development (вы увидите, как мы передаем тестовую среду позже в этой статье).

Тело makeServer

Теперь мы делаем пару вещей в теле makeServer . Давайте взглянем:

 let server = new Server({})

Мы создаем новый экземпляр класса Server и передаем ему параметр конфигурации. Содержимое параметров конфигурации помогает настроить 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() }) }, }

Во-первых, мы передаем параметр environment , который мы инициализировали в определении функции.

 models: { todo: Model, },

Следующая опция, которая является опцией models , принимает объект разных моделей, которые мы хотим, чтобы Mirage имитировал.

В приведенном выше примере нам просто нужна модель todo, которую мы создаем из класса Model.

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

Следующим вариантом является метод seed, который принимает параметр server . Метод seed помогает создавать seed (seeds — исходные данные или запись в базе данных Mirage) для наших моделей. В нашем случае, чтобы создать семена для модели todo, мы делаем:

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

наконец, у нас есть метод маршрутов, который определяет различные маршруты (маршруты — это конечные точки нашего фиктивного API), которые Mirage JS будет имитировать. Посмотрим на тело метода:

 this.namespace = "api"

эта строка устанавливает пространство имен для всех маршрутов, что означает, что к нашему маршруту todo теперь можно получить доступ из /api/todos.

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

Приведенное выше создает маршрут получения и его обработчик с использованием this.get() . Метод get() ожидает маршрут, т.е. «/todos», и функцию-обработчик, которая принимает schema в качестве аргумента. Объект схемы — это то, как вы взаимодействуете с ORM Mirage, который работает на основе базы данных Mirage JS в памяти.

Ну наконец то:

 return schema.todos.all()

Мы возвращаем список всех наших задач, используя объект схемы, который стал возможен благодаря ORM Mirage.

источник/main.js

Итак, мы закончили настройку src/server.js но Vue об этом не знает (по крайней мере, пока). Итак, давайте импортируем его в наш файл main.js следующим образом:

 import { makeServer } from "./server"

Затем мы вызываем функцию makeServer следующим образом:

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

Вышеупомянутое условное условие является защитой, чтобы if , что мираж работает только в разработке.

Настройка завершена!

Теперь мы настроили Miragejs с помощью Vue. Давайте посмотрим на это в действии. В нашем файле App.vue мы очистим содержимое и заменим его приведенным ниже фрагментом:

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

Если вы знакомы с Vue.js, в приведенном выше нет ничего нового, но для полноты картины мы делаем запрос API с использованием fetch при создании нашего компонента App.vue , а затем передаем возвращенные данные. в массив todos в состоянии нашего компонента. После этого мы используем v-for для итерации массива задач и отображения свойства содержимого каждой задачи.

Где часть Mirage JS?

Если вы заметили, в нашем компоненте App.vue мы не сделали ничего особенного для Mirage, мы просто делаем вызов API, как обычно. Эта функция Mirage действительно хороша для DX, потому что под капотом Mirage будет перехватывать любые запросы, которые соответствуют любому из маршрутов, определенных в src/server.js, пока вы находитесь в разработке.

Это очень удобно, потому что с вашей стороны не потребуется никакой работы для переключения на фактический рабочий сервер, когда вы находитесь в производственной среде, при условии, что маршруты соответствуют конечным точкам вашего производственного API.

Поэтому перезапустите сервер разработки Vue через yarn serve , чтобы протестировать Mirage JS.

Вы должны увидеть список из двух задач. Одна вещь, которую вы найдете довольно интересной, заключается в том, что нам не нужно запускать команду терминала для запуска Mirage, потому что она устраняет эти накладные расходы, работая как часть вашего приложения Vue.js.

Тестовые утилиты Mirage JS и Vue

Если вы уже используете Vue Test-utils в своем приложении Vue, вам будет интересно узнать, что Mirage может легко работать с ним для имитации сетевых запросов. Давайте посмотрим на пример, настроенный с помощью нашего приложения todos.

Мы будем использовать Jest для нашего модульного тестирования. Итак, если вы следуете этому примеру, вы можете использовать Vue CLI для установки плагина @vue/unit-jest следующим образом:

 vue add @vue/unit-jest

Вышеупомянутое установит зависимости разработки @vue/cli-plugin-unit-jest и @vue/test-utils , а также создаст каталог tests и файл jest.config.js . Это также добавит следующую команду в наш раздел scripts package.json (довольно аккуратно):

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

Давайте проверим!

Мы бы обновили наш App.vue , чтобы он выглядел так:

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

В приведенном выше фрагменте не происходит ничего действительно эпического; мы просто структурируем, чтобы обеспечить тестирование сети, которое мы будем реализовывать с помощью нашего модульного теста.

Хотя Vue CLI уже добавил для нас папку /tests , я считаю, что гораздо удобнее, когда мои тесты размещаются рядом с тестируемыми компонентами. Поэтому создайте папку /__tests__ в src/ и создайте в ней файл App.spec.js. (Это также рекомендуемый подход 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() })

Итак, чтобы настроить модульное тестирование, мы импортируем метод mount из @vue/test-utils , импортируем созданный ранее сервер Miragejs и, наконец, импортируем компонент App.vue .

Затем мы используем функцию жизненного цикла beforeEach для запуска сервера Mirage JS при прохождении тестовой среды. (Помните, мы по умолчанию установили среду development .)

Наконец, мы выключаем сервер, используя server.shutdown в методе жизненного цикла afterEach .

Наши тесты

Теперь давайте конкретизируем наш тест (мы будем использовать раздел быстрого запуска документации Mirage js. Таким образом, ваш App.spec.js будет выглядеть так:

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

Примечание . Здесь мы используем помощника (как определено в документации Mirage JS). Он возвращает обещание, которое позволяет нам узнать, когда тестируемые элементы уже находятся в DOM.

Теперь запустите yarn test:unit .

Все ваши тесты должны пройти на этом этапе.

Тестирование различных состояний сервера с помощью Mirage JS

Мы могли бы изменить наш сервер Mirage JS для проверки различных состояний сервера. Посмотрим, как.

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

Сначала мы импортируем класс Response из Mirage, затем создаем новый тестовый сценарий:

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

Запустите свой тест, и все должно пройти.

Заключение

Цель этой статьи — познакомить вас с Mirage JS и показать, как он улучшает интерфейс разработки. Мы увидели проблему, которую Mirage JS создал для решения (создание готового интерфейса без какого-либо фактического внутреннего API), и как настроить его с помощью Vue.js.

Несмотря на то, что в этой статье мы коснулись возможностей Mirage JS, я считаю, что этого достаточно для начала.

  • Вы можете просмотреть документы, а также присоединиться к серверу разногласий Mirage JS.
  • Вспомогательный репозиторий для этой статьи доступен на GitHub.

использованная литература

  • Документы Миража
  • Быстрый старт Mirage Vue