Skip to content

Add migration guide from cypress fixtures to mirage #193

@romansndlr

Description

@romansndlr

Hey all!

Why?
Because this is a very big issue for cypress developers...

When using cypress fixtures you are required to write out static JSON files in order to have mocked out responses.

I think this could be a huge selling point for mirage because you could swap using these static very limited in power JSON files to use the full power of a browser database with really minimal work.

How
So generally in order to mock out an HTTP request with cypress you would do something like this:

// createUser.json
{
    "id": 1,
    "firstName": "John",
    "lstName": "Doe"
}

// create-user.spec.js
it('Should create a new user', () => {
    // Lets assume we have an endpoint for creating a user
    // And we stub it out by telling cypress to use a fixture called createUser.json
    cy.server()
    cy.route({
      method: 'POST',
      url: '/users',
      response: 'fixture:createUser.json'
    }).as('createUser')

    // We define the values we want to enter into the inputs
    const FIRST_NAME = 'John'
    const LAST_NAME = 'Doe'

    // We find the form on the page, type in our predefined values and submit the form
    cy.get('form')
      .within(() => {
        cy.get('input[name="first_name"]').type(FIRST_NAME)
        cy.get('input[name="last_name"]').type(FIRST_NAME)
      })
      .submit()

    // We wait our app to send the request we stubbed out
    cy.wait('@createUser').then(({ response, request }) => {
      // and assert that the values that where sent to the server are the ones we typed in
      expect(request.body.firstName).to.equal(FIRST_NAME)
      expect(request.body.lastName).to.equal(LAST_NAME)

      // We want to make sure we are redirected to the correct url using the id that was created for the user
      cy.location().should(loc => {
        expect(loc.pathname).to.eq(`/users/${response.body.id}`)
      })

      // We want to make sure that the form is populated with the values that were returned from our api
      cy.get('form').within(() => {
        cy.get('input[name="first_name"]').should('have.value', FIRST_NAME)
        cy.get('input[name="last_name"]').should('have.value', LAST_NAME)
      })
    })
  })

The problem here is that if we ever change John Doe to be Jane Doe, this test would fail because the fixture JSON file doesn't change.

Luckily, not much is required to change this test to use mirage instead:

// server.js
import { Server } from 'miragejs'

new Server({
  routes() {
    this.post('/users', (schema, request) => {
      const user = JSON.parse(request.requestBody)
      return schema.users.create(user)
    })
  }
})

// create-user.spec.js
import { makeServer } from "../../src/server"

let server

beforeEach(() => {
  server = makeServer({ environment: "test" })
})

afterEach(() => {
  server.shutdown()
})

it('Should create a new user', () => {
    // Lets assume we have an endpoint for creating a user
    // And we stub it out by telling cypress to use a fixture called createUser.json
    cy.server()
    cy.route({
      method: 'POST',
      url: '/users'
      // Remove 👇👇👇 this line to tell cypress to let the request through
      // response: 'fixture:createUser.json'
      // Now we can change the user's name to anything and the test will still pass
    }).as('createUser')

    // We define the values we want to enter into the inputs
    const FIRST_NAME = 'John'
    const LAST_NAME = 'Doe'

    // We find the form on the page, type in our predefined values and submit the form
    cy.get('form')
      .within(() => {
        cy.get('input[name="first_name"]').type(FIRST_NAME)
        cy.get('input[name="last_name"]').type(FIRST_NAME)
      })
      .submit()

    // We wait our app to send the request we stubbed out
    cy.wait('@createUser').then(({ response, request }) => {
      // and assert that the values that where sent to the server are the ones we typed in
      expect(request.body.firstName).to.equal(FIRST_NAME)
      expect(request.body.lastName).to.equal(LAST_NAME)

      // We want to make sure we are redirected to the correct url using the id that was created for the user
      cy.location().should(loc => {
        expect(loc.pathname).to.eq(`/users/${response.body.id}`)
      })

      // We want to make sure that the form is populated with the values that were returned from our api
      cy.get('form').within(() => {
        cy.get('input[name="first_name"]').should('have.value', FIRST_NAME)
        cy.get('input[name="last_name"]').should('have.value', LAST_NAME)
      })
    })
  })  

So basiclly all we had to do to make the transition to mirage is define the route handler (which you need to do regradless) and remove one line from our test file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions