APIがなくても、 完全なフロントエンド機能を構築できます。

Mirage JSは、バックエンドサービスに依存することなく、完全な動作をするJavaScriptアプリケーションを構築、テスト、共有できるAPIモックライブラリです。

サーバーを作成する

Mirageは、他のフロントエンドJavaScriptコードと並行して実行されます。新しいサーバープロセスやターミナルウィンドウは必要ありません。使い慣れた開発ツールを使用して、ネットワークに対応したUIコードを作成します。

フロントエンド開発のための最高のDX

UIをハックするためだけに、面倒なバックエンド環境の設定に別れを告げましょう。Mirageは他のフロントエンドコードと並行して実行されるため、新しいインフラストラクチャを学ぶ必要はありません。

新しい共同作業者は、フロントエンドのコードベースをクローンし、npm installを実行するだけで、完全なローカルオフライン開発環境を数秒で起動して実行できます。環境変数や認証トークンは必要ありません。

import React from "react"
import ReactDOM from "react-dom"
import App from "./App"
import { createServer } from "miragejs"

createServer({
  routes() {
    this.namespace = "api"

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

ReactDOM.render(<App />, document.getElementById("root"))

Herokuでは、2015年から重要な顧客向けアプリでMirageを使用しています。これにより、開発ワークフローとテストワークフローの両方で速度を犠牲にすることなく、チームを成長させることができました。

私にとって、Mirageの真の魔法は、ユーザーの視点からテストを作成できることです。製品チームからユーザーストーリーを取得し、フロントエンドのツールチェーンから外れることなく、1:1でテストに変換します。

要するに、MirageはすべてのUI開発者にとって不可欠なツールです。

ジェイミー・ホワイト

Salesforce / Herokuのソフトウェアエンジニア

記述する 高レベルUIテスト それはあなたのネットワークコードにストレスを与えます。

Mirageを使用すると、APIの状態に関係なく、APIに対して自動テストを作成できます。アプリがブログ投稿を0件、10件、または1000件処理する方法、またはサーバーの速度が遅い場合やエラーで応答する場合の動作をテストします。

テストに面倒なモックコードや手作りのAPIレスポンスはありません。アプリケーション全体の機能を検証する現実世界のシナリオだけです。

Browsers
it("shows a message if there are no todos", async () => {
  const { getByTestId } = render(<App />)
  await waitForElementToBeRemoved(() => getByTestId("loading"))

  expect(getByTestId("no-todos")).toBeInTheDocument()
})

it("shows existing todos", async () => {
  server.createList("todo", 3)

  const { getByTestId, getAllByTestId } = render(<App />)
  await waitForElementToBeRemoved(() => getByTestId("loading"))

  expect(getAllByTestId("todo")).toHaveLength(3)
})

it("can complete a todo", async () => {
  server.create("todo", { text: "Todo 1", isDone: false })
  server.create("todo", { text: "Todo 2", isDone: false })

  const { getByTestId, getAllByTestId } = render(<App />)
  await waitForElementToBeRemoved(() => getByTestId("loading"))
  const todos = getAllByTestId("todo")
  userEvent.click(todos[1].querySelector("input[type='checkbox']"))
  await waitForElementToBeRemoved(() => getByTestId("saving"))

  expect(todos[0].querySelector('input[type="checkbox"]').checked).toBe(false)
  expect(todos[1].querySelector('input[type="checkbox"]').checked).toBe(true)
  expect(server.db.todos[1].isDone).toBe(true)
})

it("can create a todo", async () => {
  const { getByTestId } = render(<App />)
  await waitForElementToBeRemoved(() => getByTestId("loading"))

  const newTodoForm = await waitForElement(() => getByTestId("new-todo-form"))
  userEvent.type(newTodoForm.querySelector("input"), "Walk the dog")
  fireEvent.submit(getByTestId("new-todo-form"))
  await waitForElementToBeRemoved(() => getByTestId("saving"))

  const todo = getByTestId("todo")
  expect(todo.querySelector('input[type="checkbox"]').checked).toBe(false)
  expect(todo.querySelector('input[type="text"]').value).toBe("Walk the dog")
  expect(server.db.todos.length).toBe(1)
  expect(server.db.todos[0].text).toBe("Walk the dog")
})

it("shows a message if there are no todos", async () => {
  const { getByTestId } = render(<App />)
  await waitForElementToBeRemoved(() => getByTestId("loading"))

  expect(getByTestId("no-todos")).toBeInTheDocument()
})

it("shows existing todos", async () => {
  server.createList("todo", 3)

  const { getByTestId, getAllByTestId } = render(<App />)
  await waitForElementToBeRemoved(() => getByTestId("loading"))

  expect(getAllByTestId("todo")).toHaveLength(3)
})

it("can complete a todo", async () => {
  server.create("todo", { text: "Todo 1", isDone: false })
  server.create("todo", { text: "Todo 2", isDone: false })

  const { getByTestId, getAllByTestId } = render(<App />)
  await waitForElementToBeRemoved(() => getByTestId("loading"))
  const todos = getAllByTestId("todo")
  userEvent.click(todos[1].querySelector("input[type='checkbox']"))
  await waitForElementToBeRemoved(() => getByTestId("saving"))

  expect(todos[0].querySelector('input[type="checkbox"]').checked).toBe(false)
  expect(todos[1].querySelector('input[type="checkbox"]').checked).toBe(true)
  expect(server.db.todos[1].isDone).toBe(true)
})

it("can create a todo", async () => {
  const { getByTestId } = render(<App />)
  await waitForElementToBeRemoved(() => getByTestId("loading"))

  const newTodoForm = await waitForElement(() => getByTestId("new-todo-form"))
  userEvent.type(newTodoForm.querySelector("input"), "Walk the dog")
  fireEvent.submit(getByTestId("new-todo-form"))
  await waitForElementToBeRemoved(() => getByTestId("saving"))

  const todo = getByTestId("todo")
  expect(todo.querySelector('input[type="checkbox"]').checked).toBe(false)
  expect(todo.querySelector('input[type="text"]').value).toBe("Walk the dog")
  expect(server.db.todos.length).toBe(1)
  expect(server.db.todos[0].text).toBe("Walk the dog")
})

共有する 完全に機能するUI バックエンドを実行せずに。

MirageはAPIサーバー全体を現実的にモックアウトするため、バックエンドサービスを実行することなく、クリック可能なJavaScriptアプリケーションのプロトタイプを共有できます。

高価なサーバー側インフラストラクチャへの投資を開始する前に、ユーザーから質の高いフィードバックを得て、これまで以上に速く反復処理します。

正直なところ、このツールを十分に推奨することはできません。ついに、フロントエンド開発者が実際のAPIに触れることなく機能全体をプロトタイプ化およびテストするための慣用的な方法ができました。生産性は飛躍的に向上します。

Mirageの使用を開始する

Mirageは、すべての主要なJavaScriptフレームワーク、ライブラリ、およびテストランナーで動作します。