Skip to content

Latest commit

 

History

History
435 lines (321 loc) · 9.78 KB

Mock-plugin.md

File metadata and controls

435 lines (321 loc) · 9.78 KB

Go back

Xior mock plugin let you easily mock requests.

Good to know: the xior mock plugin idea inspired from axios-mock-adapter

Table of Contents

Installation

Package manager

# npm
npm install xior

# pnpm
pnpm add xior

# bun
bun add xior

# yarn
yarn add xior

Basic usage:

import xior from 'xior';
import MockPlugin from 'xior/plugins/mock';

const instance = xior.create();
const mock = new MockPlugin(instance);

mock.onGet('/api/hello').reply(200, [{ msg: 'hello' }]);
instance.get('/api/hello').then((res) => {
  console.log(res.data); // [{ msg: 'hello' }]
});

CDN

Using jsDelivr CDN:

<script src="https://cdn.jsdelivr.net/npm/xior@0.5.0/dist/xior.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xior@0.5.0/plugins/mock.umd.js"></script>

<!-- Usage -->
<script>
  const instance = xior.create();
  const mock = new xiorMock(instance);

  mock.onGet('/api/hello').reply(200, [{ msg: 'hello' }]);
  instance.get('/api/hello').then((res) => {
    console.log(res.data); // [{ msg: 'hello' }]
  });
</script>

Using unpkg CDN:

<script src="https://unpkg.com/xior@0.5.0/dist/xior.umd.js"></script>
<script src="https://unpkg.com/xior@0.5.0/plugins/mock.umd.js"></script>

<!-- Usage -->
<script>
  const instance = xior.create();
  const mock = new xiorMock(instance);

  mock.onGet('/api/hello').reply(200, [{ msg: 'hello' }]);
  instance.get('/api/hello').then((res) => {
    console.log(res.data); // [{ msg: 'hello' }]
  });
</script>

Getting Started

Mock GET requests

DELETE / HEAD / OPTIONS are same usage with GET

Mocking a GET request:

import xior from 'xior';
import MockPlugin from 'xior/plugins/mock';

const instance = xior.create();
const mock = new MockPlugin(instance);

// Mock any GET request to /users
// arguments for reply are (status, data, headers)
mock.onGet('/users').reply(
  200,
  {
    users: [{ id: 1, name: 'John Smith' }],
  },
  {
    'X-Custom-Response-Header': '123',
  }
);

instance.get('/users').then(function (response) {
  console.log(response.data);
  console.log(response.headers.get('X-Custom-Response-Header')); // 123
});

Mocking a GET request with specific parameters:

import xior from 'xior';
import MockPlugin from 'xior/plugins/mock';

const instance = xior.create();
const mock = new MockPlugin(instance);

// Mock GET request to /users when param `searchText` is 'John'
// arguments for reply are (status, data, headers)
mock.onGet('/users', { params: { searchText: 'John' } }).reply(200, {
  users: [{ id: 1, name: 'John Smith' }],
});

instance.get('/users', { params: { searchText: 'John' } }).then(function (response) {
  console.log(response.data);
});

Reject all GET requests with HTTP 500:

mock.onGet().reply(500);

Mock POST requests

PUT / PATCH are same usage with POST

Mocking a POST request:

import xior from 'xior';
import MockPlugin from 'xior/plugins/mock';

const instance = xior.create();
const mock = new MockPlugin(instance);

// Mock any POST request to /users
// arguments for reply are (status, data, headers)
mock.onPost('/users').reply(
  200,
  {
    users: [{ id: 1, name: 'John Smith' }],
  },
  {
    'X-Custom-Response-Header': '123',
  }
);

instance.post('/users').then(function (response) {
  console.log(response.data);
  console.log(response.headers.get('X-Custom-Response-Header')); // 123
});

Mocking a POST request with specific parameters and data:

import xior from 'xior';
import MockPlugin from 'xior/plugins/mock';

const instance = xior.create();
const mock = new MockPlugin(instance);

// Mock POST request to /users when param `searchText` is 'John'
// arguments for reply are (status, data, headers)
mock.onPost('/users', null, { params: { searchText: 'John' } }).reply(200, {
  users: [{ id: 1, name: 'John Smith' }],
});

instance.get('/users', null, { params: { searchText: 'John' } }).then(function (response) {
  console.log(response.data);
});

Reject all POST requests with HTTP 500:

mock.onPost().reply(500);

Using regexp

mock.onGet(/\/users\/\d+/).reply(function (config) {
  // the actual id can be grabbed from config.url

  return [200, {}];
});

Using chainning

Chaining is also supported:

mock.onGet('/users').reply(200, users).onGet('/posts').reply(200, posts);

.replyOnce() can be used to let the mock only reply once:

mock
  .onGet('/users')
  .replyOnce(200, users) // After the first request to /users, this handler is removed
  .onGet('/users')
  .replyOnce(500); // The second request to /users will have status code 500
// Any following request would return a 404 since there are
// no matching handlers left

Mock Any requests

Mocking any request to a given url

// mocks GET, POST, ... requests to /foo
mock.onAny('/foo').reply(200);

.onAny can be useful when you want to test for a specific order of requests:

// Expected order of requests:
const responses = [
  ['GET', '/foo', 200, { foo: 'bar' }],
  ['POST', '/bar', 200],
  ['PUT', '/baz', 200],
];

// Match ALL requests
mock.onAny().reply((config) => {
  const [method, url, ...response] = responses.shift();
  if (config.url === url && config.method.toUpperCase() === method) return response;
  // Unexpected request, error out
  return [500, {}];
});

.passthrough() and options {onNoMatch: 'passthrough'}

.passThrough() forwards the matched request over network

// Mock POST requests to /api with HTTP 201, but forward
// GET requests to server
mock
  .onPost(/^\/api/)
  .reply(201)
  .onGet(/^\/api/)
  .passThrough();

Recall that the order of handlers is significant:

// Mock specific requests, but let unmatched ones through
mock.onGet('/foo').reply(200).onPut('/bar', { xyz: 'abc' }).reply(204).onAny().passThrough();

Note that passThrough requests are not subject to delaying by delayResponse.

If you set onNoMatch option to passthrough all requests would be forwarded over network by default

// Mock all requests to /foo with HTTP 200, but forward
// any others requests to server
var mock = new MockPlugin(instance, { onNoMatch: 'passthrough' });

mock.onAny('/foo').reply(200);

options {onNoMatch: 'throwException'}

Using onNoMatch option with throwException to throw an exception when a request is made without match any handler. It's helpful to debug your test mocks.

const mock = new MockPlugin(instance, { onNoMatch: 'throwException' });

mock.onAny('/foo').reply(200);

axios.get('/unexistent-path');

// Exception message on console:
//
// Could not find mock for:
// {
//   "method": "get",
//   "url": "/unexistent-path"
// }

Mock requests errors

Network error:

// Returns a failed promise with Error('Network Error');
mock.onGet('/users').networkError();
// networkErrorOnce can be used to mock a network error only once
mock.onGet('/users').networkErrorOnce();

Timeout error:

// Returns a failed promise with Error `XiorTimeoutError`
mock.onGet('/users').timeout();
// timeoutOnce can be used to mock a timeout only once
mock.onGet('/users').timeoutOnce();

history

The history property allows you to enumerate existing xior request objects. The property is an object of verb keys referencing arrays of request objects.

It's useful for testing.

import xior from 'xior';
import MockPlugin from 'xior/plugins/mock';

const instance = xior.create();
const mock = new MockPlugin(instance);

describe('Feature', () => {
  it('records the xior config each time the handler is invoked', function () {
    mock.onAny('/foo').reply(200);

    return instance.get('/foo').then(function (response) {
      assert.equal(mock.history.get?.length, 1);
      assert.equal(mock.history.get?.[0].method, 'GET');
      assert.equal(mock.history.get?.[0].url, '/foo');
    });
  });
});

You can clear the history with resetHistory:

mock.resetHistory();

handlers

The handlers property allows you to enumerate existing xior response objects.

It's useful for testing.

import xior from 'xior';
import MockPlugin from 'xior/plugins/mock';

const instance = xior.create();
const mock = new MockPlugin(instance);

describe('Feature', () => {
  it('resets the registered mock handlers', function () {
    mock.onGet('/foo').reply(200);
    assert.equal(mock.handlers['get'] && mock.handlers['get'].length > 0, true);

    mock.reset();
    assert.equal(mock.handlers['get'], undefined);
  });
});

You can clear the handlers with resetHandlers:

mock.resetHandlers();

Reset mock history, handlers and the plugin

import xior from 'xior';
import MockPlugin from 'xior/plugins/mock';

const instance = xior.create();
const mock = new MockPlugin(instance);

// reset history
mock.resetHistory();

// reset handlers
mock.resetHandlers();

// reset history and handlers
mock.reset();

// remove the mock plugin from instance
mock.restore();

Go back