包详细信息

egg-mock

eggjs81.4k5.15.1

mock server for egg

egg, mock

自述文件

egg-mock

NPM version Node.js CI Test coverage npm download

Mock library for testing Egg applications, plugins and custom Egg frameworks with ease. egg-mock inherits all APIs from node_modules/mm, offering more flexibility.

Install

$ npm i egg-mock --save-dev

Usage

Create testcase

Launch a mock server with mm.app

// test/index.test.js
const path = require('path');
const mm = require('egg-mock');

describe('some test', () => {
  let app;
  before(() => {
    app = mm.app({
      baseDir: 'apps/foo'
    });
    return app.ready();
  })
  after(() => app.close());

  it('should request /', () => {
    return app.httpRequest()
      .get('/')
      .expect(200);
  });
});

Retrieve Agent instance through app.agent after mm.app started.

Using mm.cluster launch cluster server, you can use the same API as mm.app;

Test Application

baseDir is optional that is process.cwd() by default.

before(() => {
  app = mm.app();
  return app.ready();
});

Test Framework

framework is optional, it's node_modules/egg by default.

before(() => {
  app = mm.app({
    baseDir: 'apps/demo',
    framework: true,
  });
  return app.ready();
});

Test Plugin

If eggPlugin.name is defined in package.json, it's a plugin that will be loaded to plugin list automatically.

before(() => {
  app = mm.app({
    baseDir: 'apps/demo',
  });
  return app.ready();
});

You can also test the plugin in different framework, e.g. test aliyun-egg and framework-b in one plugin.

describe('aliyun-egg', () => {
  let app;
  before(() => {
    app = mm.app({
      baseDir: 'apps/demo',
      framework: path.join(__dirname, 'node_modules/aliyun-egg'),
    });
    return app.ready();
  });
});

describe('framework-b', () => {
  let app;
  before(() => {
    app = mm.app({
      baseDir: 'apps/demo',
      framework: path.join(__dirname, 'node_modules/framework-b'),
    });
    return app.ready();
  });
});

If it's detected as an plugin, but you don't want it to be, you can use plugin = false.

before(() => {
  app = mm.app({
    baseDir: 'apps/demo',
    plugin: false,
  });
  return app.ready();
});

API

mm.app(options)

Create a mock application.

mm.cluster(options)

Create a mock cluster server, but you can't use API in application, you should test using supertest.

const mm = require('egg-mock');
describe('test/app.js', () => {
  let app, config;
  before(() => {
    app = mm.cluster();
    return app.ready();
  });
  after(() => app.close());

  it('some test', () => {
    return app.httpRequest()
      .get('/config')
      .expect(200)
  });
});

You can disable coverage, because it's slow.

mm.cluster({
  coverage: false,
});

mm.env(env)

Mock env when starting

// production environment
mm.env('prod');
mm.app({
  cache: false,
});

Environment list https://github.com/eggjs/egg-core/blob/master/lib/loader/egg_loader.js#L82

mm.consoleLevel(level)

Mock level that print to stdout/stderr

// DON'T log to terminal
mm.consoleLevel('NONE');

level list: DEBUG, INFO, WARN, ERROR, NONE

mm.home(homePath)

mock home directory

mm.restore()

restore all mock data, e.g. afterEach(mm.restore)

options

Options for mm.app and mm.cluster

baseDir {String}

The directory of application, default is process.cwd().

mm.app({
  baseDir: path.join(__dirname, 'fixtures/apps/demo'),
})

You can use a string based on $CWD/test/fixtures for short

mm.app({
  baseDir: 'apps/demo',
})

framework {String/Boolean}

The directory of framework

mm.app({
  baseDir: 'apps/demo',
  framework: path.join(__dirname, 'fixtures/egg'),
})

It can be true when test an framework

plugin

The directory of plugin, it's detected automatically.

mm.app({
  baseDir: 'apps/demo',
})

plugins {Object}

Define a list of plugins

cache {Boolean}

Determine whether enable cache. it's cached by baseDir.

clean {Boolean}

Clean all logs directory, default is true.

If you are using ava, disable it.

app.mockLog([logger]) and app.expectLog(str[, logger]), app.notExpectLog(str[, logger])

Assert some string value in the logger instance. It is recommended to pair app.mockLog() with app.expectLog() or app.notExpectLog(). Using app.expectLog() or app.notExpectLog() alone requires dependency on the write speed of the log. When the server disk is high IO, unstable results will occur.

it('should work', async () => {
  app.mockLog();
  await app.httpRequest()
    .get('/')
    .expect('hello world')
    .expect(200);

  app.expectLog('foo in logger');
  app.expectLog('foo in coreLogger', 'coreLogger');
  app.expectLog('foo in myCustomLogger', 'myCustomLogger');

  app.notExpectLog('bar in logger');
  app.notExpectLog('bar in coreLogger', 'coreLogger');
  app.notExpectLog('bar in myCustomLogger', 'myCustomLogger');
});

app.httpRequest()

Request current app http server.

it('should work', () => {
  return app.httpRequest()
    .get('/')
    .expect('hello world')
    .expect(200);
});

See supertest to get more APIs.

.unexpectHeader(name)

Assert current response not contains the specified header

it('should work', () => {
  return app.httpRequest()
    .get('/')
    .unexpectHeader('set-cookie')
    .expect(200);
});

.expectHeader(name)

Assert current response contains the specified header

it('should work', () => {
  return app.httpRequest()
    .get('/')
    .expectHeader('set-cookie')
    .expect(200);
});

app.mockContext(options)

const ctx = app.mockContext({
  user: {
    name: 'Jason'
  }
});
console.log(ctx.user.name); // Jason

app.mockContextScope(fn, options)

await app.mockContextScope(async ctx => {
  console.log(ctx.user.name); // Jason
}, {
  user: {
    name: 'Jason'
  }
});

app.mockCookies(data)

app.mockCookies({
  foo: 'bar'
});
const ctx = app.mockContext();
console.log(ctx.getCookie('foo'));

app.mockHeaders(data)

Mock request header

app.mockSession(data)

app.mockSession({
  foo: 'bar'
});
const ctx = app.mockContext();
console.log(ctx.session.foo);

app.mockService(service, methodName, fn)

it('should mock user name', function* () {
  app.mockService('user', 'getName', function* (ctx, methodName, args) {
    return 'popomore';
  });
  const ctx = app.mockContext();
  yield ctx.service.user.getName();
});

app.mockServiceError(service, methodName, error)

You can mock an error for service

app.mockServiceError('user', 'home', new Error('mock error'));

app.mockCsrf()

app.mockCsrf();

return app.httpRequest()
  .post('/login')
  .expect(302);

app.mockHttpclient(url, method, data)

Mock httpclient request, e.g.: ctx.curl

app.get('/', function*() {
  const ret = yield this.curl('https://eggjs.org');
  this.body = ret.data.toString();
});

app.mockHttpclient('https://eggjs.org', {
  // can be buffer / string / json / function
  // will auto convert to buffer
  // follow options.dataType to convert
  data: 'mock egg',
});
// app.mockHttpclient('https://eggjs.org', 'get', mockResponse); // mock get
// app.mockHttpclient('https://eggjs.org', [ 'get' , 'head' ], mockResponse); // mock get and head
// app.mockHttpclient('https://eggjs.org', '*', mockResponse); // mock all methods
// app.mockHttpclient('https://eggjs.org', mockResponse); // mock all methods by default
// app.mockHttpclient('https://eggjs.org', 'get', function(url, opt) { return 'xxx' }); // support fn

return app.httpRequest()
  .post('/')
  .expect('mock egg');

You can also use Regular Expression for matching url.

app.mockHttpclient(/\/users\/[a-z]$/i, {
  data: {
    name: 'egg',
  },
});

You can alse mock agent.httpclient

app.agent.mockHttpclient('https://eggjs.org', {
  data: {
    name: 'egg',
  },
});

Bootstrap

We also provide a bootstrap file for applications' unit test to reduce duplicated code:

const { app, mock, assert } = require('egg-mock/bootstrap');

describe('test app', () => {
  it('should request success', () => {
    // mock data will be restored each case
    mock.data(app, 'method', { foo: 'bar' });
    return app.httpRequest()
      .get('/foo')
      .expect(res => {
        assert(!res.headers.foo);
      })
      .expect(/bar/);
  });
});

describe('test ctx', () => {
  it('can use ctx', async function() {
    const res = await this.ctx.service.foo();
    assert(res === 'foo');
  });
});

We inject ctx to every test case, so you can use app.currentContext in your test case. and the first call of app.mockContext will reuse app.currentContext.

const { app, mock, assert } = require('egg-mock/bootstrap');

describe('test ctx', () => {
  it('should can use ctx', () => {
    const ctx = app.currentContext;
    assert(ctx);
  });

  it('should reuse ctx', () => {
    const ctx = app.currentContext;
    // first call will reuse app.currentContext
    const mockCtx = app.mockContext();
    assert(ctx === mockCtx);
    // next call will create a new context
    // multi call app.mockContext will get wrong context with app.currentContext
    // so we recommend to use app.mockContextScope
    const mockCtx2 = app.mockContext();
    assert(ctx !== mockCtx);
  });
});

And if you use mm.app to bootstrap app, you can manually call setGetAppCallback, then egg-mock will inject ctx for each test case.

// test/.setup.js
const mm = require('egg-mock');
const path = require('path');
before(async function() {
  const app = this.app = mm.app();
  mm.setGetAppCallback(() => {
    return app;
  });
  await app.ready();
});


// test/index.test.js
it('should work', function() {
  // eslint-disable-next-line no-undef
  assert(this.app.currentContext);
});

env for custom bootstrap

EGG_BASE_DIR: the base dir of egg app EGG_FRAMEWORK: the framework of egg app

Questions & Suggestions

Please open an issue here.

License

MIT

Contributors

Contributors

Made with contributors-img.

更新日志

Changelog

5.15.1 (2024-12-12)

Bug Fixes

5.15.0 (2024-12-10)

Features

5.14.0 (2024-12-09)

Features

  • detect-port@2, is-type-of@2, get-ready@3 (#175) (0364af8)

5.13.0 (2024-12-07)

Features

5.12.5 (2024-07-05)

Bug Fixes

  • should run restore in the current event loop (#172) (1f9fc01)

5.12.4 (2024-07-04)

Bug Fixes

5.12.3 (2024-07-02)

Bug Fixes

5.12.2 (2024-07-02)

Bug Fixes

5.12.1 (2024-07-02)

Bug Fixes

  • support httpclient mock on allowH2 = true (#168) (3a434bb)

5.12.0 (2024-06-02)

Features

  • change backgroundTasksFinished method from private to public (#163) (86b4d45)

5.11.0 (2024-06-02)

Features

5.10.9 (2023-11-08)

Bug Fixes

  • allow to call mockHttpclient multi times (#165) (370e42d)

5.10.8 (2023-06-21)

Bug Fixes

  • fix mocha failed title for inject_ctx (#162) (f6f59ac)

5.10.7 (2023-05-29)

Bug Fixes

5.10.6 (2023-02-22)

Bug Fixes

5.10.5 (2023-02-16)

Bug Fixes

5.10.4 (2023-01-31)

Bug Fixes

5.10.3 (2023-01-30)

Bug Fixes

  • inject failed should make suite/test failed (#154) (f9f2d4c)

5.10.2 (2023-01-30)

Bug Fixes

  • make sure app ready on parallel mode (#155) (83c600e)

5.10.1 (2023-01-29)

Bug Fixes

5.10.0 (2023-01-28)

Features

5.9.4 (2023-01-18)

Bug Fixes

  • use originalUrl to check mock call function request (#149) (abe1c07)

5.9.3 (2023-01-18)

Bug Fixes

5.9.2 (2023-01-17)

Bug Fixes

5.8.4 (2023-01-12)

Bug Fixes

  • only await app ready when app exists (#145) (f4ed458)

5.8.3 (2023-01-11)

Bug Fixes

  • app should wait for agent ready on parallel mode (#144) (205e836)

5.8.2 (2023-01-10)

Bug Fixes

  • ignore bootstrap error on non egg project (#142) (880c282)

5.8.1 (2023-01-09)

Bug Fixes

5.8.0 (2023-01-09)

Features

  • use mocha global hook to register before/after (#140) (9ef65de)

5.7.1 (2023-01-07)

Bug Fixes

5.7.0 (2023-01-03)

Features

5.6.0 (2023-01-03)

Features

5.5.0 (2022-12-28)

Features


5.4.0 / 2022-12-14

features

5.3.0 / 2022-12-09

features

5.2.1 / 2022-11-11

fixes

5.2.0 / 2022-11-08

features

5.1.0 / 2022-11-04

features

5.0.2 / 2022-10-09

fixes

others

5.0.1 / 2022-09-29

features

5.0.0 / 2022-09-29

features

4.2.1 / 2022-05-17

features

others

4.2.0 / 2021-12-17

features

4.1.0 / 2021-04-05

features

others

4.0.1 / 2020-08-19

features

4.0.0 / 2020-03-01

features

3.25.1 / 2020-01-17

fixes

3.25.0 / 2019-12-12

features

fixes

3.24.2 / 2019-11-07

fixes

3.24.1 / 2019-09-30

fixes

3.24.0 / 2019-09-26

features

3.23.2 / 2019-09-10

fixes

3.23.1 / 2019-05-20

fixes

3.23.0 / 2019-05-20

features

3.22.4 / 2019-05-06

fixes

3.22.3 / 2019-05-06

fixes

  • [6174f9b] - fix: throw error when an egg plugin test is using bootstrap (#100) (TZ | 天猪 <atian25@qq.com>)

3.22.2 / 2019-04-10

fixes

3.22.1 / 2019-03-12

fixes

3.22.0 / 2019-03-11

features

fixes

3.21.0 / 2018-12-27

features

* [[`93f8009`](https://github.com/eggjs/egg-mock/commit/93f8009c2f4c7d7f24b361f4713e035a2f993134)] - feat: cluster mock support result (#92) (TZ <<atian25@qq.com>>)
* [[`be3d146`](https://github.com/eggjs/egg-mock/commit/be3d1466bf438a379b85429c40c510d6be7ecc26)] - feat: bootstrap support run on jest env (#93) (fengmk2 <<fengmk2@gmail.com>>)

3.20.1 / 2018-09-17

fixes

others

3.20.0 / 2018-08-30

features

3.19.7 / 2018-08-28

fixes

3.19.6 / 2018-08-24

fixes

3.19.5 / 2018-08-24

fixes

3.19.4 / 2018-08-24

  • feat: .d.ts 新增继承自 mm 的 api (#81)

3.19.3 / 2018-08-16

fixes

3.19.2 / 2018-08-07

fixes

3.19.1 / 2018-08-07

fixes

3.19.0 / 2018-08-06

features

3.18.0 / 2018-08-03

features

others

3.17.3 / 2018-07-14

  • types: add bootstrap.d.ts (#75)

3.17.2 / 2018-05-21

others

3.17.1 / 2018-04-21

  • fix: remove options.typescript support (#73)

3.17.0 / 2018-03-30

  • feat: support ts from env and pkg (#71)

3.16.0 / 2018-03-28

  • feat: support ts (#70)
  • fix: mockSession save should not be enumerable (#69)

3.15.1 / 2018-03-20

fixes

3.15.0 / 2018-03-08

features

3.14.1 / 2018-02-28

fixes

others

3.14.0 / 2017-12-12

others

3.13.1 / 2017-10-17

fixes

3.13.0 / 2017-10-10

features

3.12.2 / 2017-09-22

fixes

others

3.12.1 / 2017-09-13

others

3.12.0 / 2017-09-12

others

3.11.0 / 2017-09-11

features

3.10.0 / 2017-08-30

features

3.9.1 / 2017-08-14

fixes

3.9.0 / 2017-08-02

features

3.8.0 / 2017-06-21

  • deps: upgrade dependencies (#51)
  • test: disable coverage when mm.cluster (#50)

3.7.2 / 2017-06-07

  • fix(httpclient): miss headers on options when emit response (#49)

3.7.1 / 2017-06-01

  • fix: detect prop object type can be non string (#48)

3.7.0 / 2017-05-18

  • feat: support prerequire files (#46)

3.6.1 / 2017-05-11

  • fix: ignore all error on cluster mock restore (#45)

3.6.0 / 2017-05-10

  • chore: add tsd (#43)
  • feat: support mock function on cluster mode (#44)
  • deps: upgrade dependencies (#42)

3.5.0 / 2017-04-25

  • feat: mockUrllib support async function (#41)

3.4.0 / 2017-04-17

  • feat: should pass when emit egg-ready (#39)

3.3.0 / 2017-04-15

  • feat: add app.httpRequest() test helper (#38)

3.2.0 / 2017-03-14

  • feat: mockHttpClient support mock multi methods (#35)
  • test: remove userrole (#34)

3.1.2 / 2017-03-05

  • fix: should pass all arguments when mockCookies (#33)

3.1.1 / 2017-03-04

  • fix: egg-mock is not a framework (#32)

3.1.0 / 2017-03-02

  • feat: use framework instead of customEgg (#31)

3.0.1 / 2017-02-22

  • fix: app.close in right order (#30)

3.0.0 / 2017-02-13

  • deps: upgrade egg (#29)
  • fix: bind messenger with app and agent (#28)
  • feat: [BREAKING_CHANGE] can get error from .ready() (#27)
  • test: remove unuse codes (#26)

2.4.0 / 2017-02-08

  • feat: listen error that thrown when app init (#25)

2.3.1 / 2017-01-26

  • fix: improve proxy handler and event listener (#24)

2.3.0 / 2017-01-25

  • feat: cluster-client support for mm.app (#23)

2.2.0 / 2017-01-25

  • feat: reimplement mm.app (#22)

2.1.0 / 2017-01-16

  • feat: support read framework from package.json (#20)

2.0.0 / 2017-01-12

  • refactor: use mockHttpclient instead of mockUrllib (#19)

1.3.0 (deprecated) / 2017-01-12

  • refactor: use mockHttpclient instead of mockUrllib (#19)

1.2.1 / 2017-01-09

  • fix: can't override data when mockContext(data) (#18)
  • fix: replace the internal link into an github link in the env comment. (#17)

1.2.0 / 2016-11-11

  • feat: try to lookup egg that will be the default customEgg (#16)
  • fix: don't use cache when app from cache is closed (#15)

1.1.0 / 2016-11-02

  • feat: add mm.home (#14)

1.0.0 / 2016-11-01

  • test: add testcase (#10)

0.0.8 / 2016-10-25

  • feat: wait 10ms to close app (#13)

0.0.7 / 2016-10-25

  • feat: should close agent when app close (#12)

0.0.6 / 2016-10-24

  • feat: cluster should wait process exit (#11)
  • docs:update readme (#9)
  • docs: update readme

0.0.5 / 2016-10-11

  • feat: pass opt to coffee (#7)

0.0.4 / 2016-08-16

  • fix: add eggPath for new egg (#5)