Testing

Testing a component or code using CoreQL could be done with the Jest Fetch Mock package or mirage.js.

Mirage is the recommended way for projects, however, Jest Fetch Mock is better for simple projects or projects with a big API that will require more work to recreate it using Mirage.

Using Jest Fetch Mock

This library is the easiest way to do it, it requires little setup and you can set what every fetch should reply on a per-test basis.

First, install it.

yarn add jest-fetch-mock

In your setup tests file, create one if you don't have it, add the following:

import fetch from 'jest-fetch-mock';
global.fetch = fetch;

If you are using TypeScript add this:

import { GlobalWithFetchMock } from 'jest-fetch-mock';
const customGlobal: GlobalWithFetchMock = global as GlobalWithFetchMock;
customGlobal.fetch = require('jest-fetch-mock');
customGlobal.fetchMock = customGlobal.fetch;

Now in your tests, before rendering a component using useResource or useCollection, or before calling a function using some API Client method add the following line:

fetch.once(JSON.stringify(mockData));

This will use mockData as the response of the next fetch call.

For more information and features read the package readme.

Mirage.js

Mirage is more complex than Jest Fetch Mock but at the same time is more powerful. The idea of this library is to create a mocked API in-memory which will intercept all your requests, this way you could configure it to reply to certain endpoints using fake data.

First, install it with:

yarn add miragejs

Then create a make-server.js file somewhere in your application with something similar to this one:

import { Server, Model, Factory, JSONAPISerializer } from 'miragejs';
import { camelize } from "inflected";
import faker from 'faker';
export default function makeServer({
environment = 'development',
trackRequests = false,
}) {
return new Server({
environment,
trackRequests,
serializers: {
// use the JSONAPISerializer to make Mirage follow the JSON:API spec
application: JSONAPISerializer.extend({
alwaysIncludeLinkageData: true,
keyForAttribute(attr) {
// use camel case for attribute keys
return camelize(attr);
},
}),
},
models: {
users: Model,
},
factories: {
// A factory to create new users
users: Factory.extend({
avatarUrl() {
return faker.internet.avatar();
},
firstName() {
return faker.name.firstName();
},
lastName() {
return faker.name.lastName();
},
fullName() {
return faker.name.findName(this.firstName, this.lastName);
},
email() {
return faker.internet.email(this.firstName, this.lastName, 'able.co');
},
}),
},
routes() {
// by default CoreQL uses api/v2 but you could change this
// using an environment variable
this.namespace = 'api/v2';
// handle all possible /users route
this.resource('users');
// any other route will passthrough Mirage and reach the network
this.passthrough();
},
});
}

Now in your tests import it.

import makeServer from './make-server';

And then create a new instance per test using beforeEach and afterEach.

let server;
beforeEach(() => {
// create a new server before each test
// with the test environment this will
// reduce latency to 0
server = makeServer({ environment: 'test' });
});
afterEach(() => {
// shutdown the server after each test
server.shutdown();
});

And in each test ask the server to create users.

test('Render list of users', () => {
server.createList('user', 10);
// here test your component fetching `/api/users`
});

With this, you don't need to think anymore about the data you will need a per-test basis, instead Mirage is creating it for you when you request it to do it.