Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support local server for complex testing scenarios #79

Closed
4 tasks
kettanaito opened this issue Mar 23, 2020 · 2 comments · Fixed by #99
Closed
4 tasks

Support local server for complex testing scenarios #79

kettanaito opened this issue Mar 23, 2020 · 2 comments · Fixed by #99

Comments

@kettanaito
Copy link
Member

kettanaito commented Mar 23, 2020

This issue originates from #77

What:

I suggest to add a support for spawning a local server for the purpose of testing.

Why:

There are complex test scenarios (such as "response patching") that assert against an actual server implementation. Relying on third-party servers brings a factor of instability to the CI pipeline of MSW. Having a local server for the sake of testing sounds like a viable option.

The local server can also replace any external dependencies and be used as an actual running server. This is something to consider.

How:

  • Write a utility function that spawns an Express server, accepts the routes and returns a Promise that resolves whenever the server is up and running (spawn at port 0 for the server to always have a dedicated port)
  • Return utility functions to perform any request against the current instance of the server (not to bind test to any specific ports)
  • Adjust the response-matching.test.ts and any other tests that require an actual server to use the introduced local server implementation
  • Close the server afterAll() test suites are finished
@kettanaito
Copy link
Member Author

kettanaito commented Mar 23, 2020

This is how I see such setup working:

// Do not confuse with the "spawnServer" utility already present
// to spawn a Webpack Dev Server. Naming is hard.
import { spawnServer } from '../utils/spawnServer'

let server

beforeAll(() => {
  server = spawnServer(app => {
    app.post('/users', (req, res) => {
      res.status(301).json({ actual: 'response' })
    })
  })
})

afterAll(() => {
  // Needs to return a Promise.
  // If Express API doesn't do that, wrap in a custom function.
  return server.instance.close()
})

describe('Test case', () => {
  it("scenario", async () => {
    // Abstracted API to get the proper route in order to not rely
    // on exact server port number.
    const REQUEST_URL = server.getRoute('/users')
    api.page.evaluate((url) => fetch(url, { method: 'POST' }), REQUEST_URL)
    // continue with assertions...
  })
})

@kettanaito
Copy link
Member Author

Since MSW already has a spawnServer utility function that's responsible for spawning a temporary WDS for the purpose of having a client page to load in Puppeteer, this task may be a matter of spawnServer accepting a parameter that would modify the WDS's app instance to declare the necessary routes.

spawnServer('/path/to/file.mocks.ts', {
  withRoutes(app) {
    app.post('/api/mock', (req, res) => {
      res.status(200).json({ response: true })
    })
  }
})

The benefits we get from entwining this logic into existing spawnServer:

  • Manage only one instance of server that acts as both client-side page and a mock of an actual server implementation to assert test scenarios that requires such (i.e. Response patching)
  • Have a single point of control over the server's lifecycle (it reports back its port number and a cleanup function, making its detection and termination easier inside tests)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant