Mirage is extracted it from an addon that's been widely used in the Ember ecosystem for the past 4 years, at companies like Apple, Heroku, Square and Footlocker.
Nearly all frontends need to talk to an API, no matter what framework they're built with! So over the past year I've made Mirage work with any tool or test runner.
I really believe deeply in the frontend-first workflow, and Mirage makes that easier than ever. If it sounds interesting to you, check out the lib + let me know what you think!
If you can divide acquisition from usage, I wonder how much less effort you need to put into API mocking.
Ages ago and shortly after I started testing, was the last time I had to do any low-level HTTP response processing. My coworkers could not fathom why I had divided the parsing and networking code into completely separate sections. Then I showed them how stupid-simple most of the tests were, instead of the convoluted mess of integration tests I'd walked into.
Hand the payload to I/O-free code immediately. You've done the hardest part at this point. Mocking out the network layer in any of half a dozen ways is a cakewalk in comparison.
Splitting conditional logic from dependencies makes code so much easier to test. If you can do that, there's no need to mock anything. You can just pass simple data objects into your conditional logic for testing, and use a handful of integration tests to validate the end-to-end flow.
With the exception of callbacks (and async solves that for single-issue scenarios), arguments don't need to be mocked. They're just arguments.
But being able to go down to the HTTP level and mock responses there provides a different benefit. You are able to do end to end tests but isolated to your own service. I always do that (alongside unit tests) so I can even catch errors outside of my code base, i.e. in my dependencies.
Instead of
// MyComponent.js
const users = await fetch(...
Use this // MyComponent.js
const users = await api.getUsers()
// api.js
export default {
getUsers() {
return fetch(...
}
}
To mock, you replace the entire api module (or individual functions).I am sure that you can do all without Mirage and I am sure that your solution might fit your project best, but I doubt that it will take you the same amount of effort
(I have been using Mirage for the past 4 years and I love it)
https://miragejs.com/docs/getting-started/introduction
"Use a client-side interceptor to handle your app's network requests. ... This is the most flexible approach, but it requires you to start from scratch in each project, and leaves it up to you to enforce conventions across your apps."
"Importantly, because Mirage mocks the HTTP boundary instead of the JavaScript code your app uses to make network requests, you never need to modify your application code to account for whether your app is talking to Mirage or to your real production backend."
Imagine that fetch suddenly has a bug (extreme example but it could be another open-source library). Your tests above wouldn't catch it.
I always strive to do at least a few integration tests like these and not stand purely on individual unit tests.
I don't know how many times mocking up a UI I start to throw some random JS objects in a file and then inevitably after a few hours, those random JS objects are unmanageable and contain very small differences between what my API will deliver.
Using Mirage from the start of projects has made my life a lot easier, it also provides a nice sanity check between what the backend delivers and what the frontend actually expects.
I have another question. Mirage is installed as a dev dependency. But all the examples show it being used in the application code. Do you maintain a separate branch without the import of Server, etc? Or is webpack smart enough to remove all imports/usage of dev dependencies in the prod build? I don't think I've ever imported dev dependencies into app code before.
For that matter, how does it provide a sanity check between what the back end delivers and the front end expects? Do you mean compared to coding to a spec with no mocking? Like when the back end doesn't exist yet?
Clearly I'm missing something. Could be the sleep deprivation.
Even so, there are teams that have used tools like Pact to perform contract testing, ensuring their Mirage server and their production API never fall out of sync. Even more exciting to me would be using something like Typescript to verify the API contract at compile-time (also something that others have been exploring).
As far as only running Mirage during development, the Ember addon does this but we need to document how to do this in the general case. When you build your app for production Mirage should not be in any application code, nor should the miragejs library be included in your bundle. Webpack is capable of this, we just need to document it.
Mirage is flexible enough to match any backend API – this is where it shines in comparison to tools like json-server. With Mirage the goal is to mock out your exact production API; its serializers and route handlers can be customized to match any API format. Often teams using Mirage reach agreement about the shape of their API beforehand, precisely so that the frontend team can move and build the UI without having to wait on the API to be ready.
Indeed, Mirage can even be thought of as a communication tool that helps impose conventions and consistency on the API layer, making both the frontend developers and the backend developers happier.
if(__DEV__) {
require("loadApiMocking");
}
Agreed that there'd be work to do to keep real code responses and mocked responses in sync, but there's probably ways to automate that if you want. In fact, I can hypothetically imagine some way to introspect OpenAPI schema files and configure Mirage accordingly.The team I work on have been using Mirage with GraphQL for 6 months or so and GraphQL’s tooling almost entirely addresses this question. There will still be false positives in API behaviour (you can never have a completely accurate simulation) but you can get an incredible degree of confidence at a startlingly low cost, with a delight developer experience to boot. Similar strategies could no doubt be employed for JSONSchema, Swagger, or Pact tooling.
Working on a React project recently, I was surprised that there wasn't an option like mirage, but now that there is, I highly recommend it!
Now make a component on top that runs a network request and injects the network response into it.
Now you have a reusable component independent of the api. Your network function can be tested individually. Your top level component doesn’t need testing as that is the part that would be mocked.
You can now test your actual component without any mocking.
If you need some dummy data to show before the backend team is ready, this is trivial. Guess I’m just not a Big enough mocking fan to ever need a library for what is such a small thing in my experience
Colorizing[1] the console logs for quickly parsing success and failure might be a nice addition. [1]: https://developers.google.com/web/tools/chrome-devtools/cons...
edit: grammar
Glad to see something like mirage solving this across all different types of API frameworks.
Does anyone have any suggestions on a way to start with an OpenAPI spec and end up with a mock data set? With Mirage it seems easy enough to mock our API directly from scratch, but if we could save a few steps and go from OpenAPI spec to mocked front end that would be bliss.
I have been using https://github.com/nock/nock in Node.js for ages and I love it as well.
Much appreciated Sam and much love ️
So you install it as a dev dependency via npm.
So is it running ... with the client app as a proxy between the client application and just waiting for the API requests and taking those responding?
Is it possible to configure some delay in responses?
You can also configure a universal delay if you’re using mirage in development and want to get a feel for your app with a certain amount of latency.