Détail du package

@eggjs/mock

eggjs3516.0.7

mock server plugin for egg

egg, mock

readme

@eggjs/mock

NPM version Node.js CI Test coverage npm download Node.js Version PRs Welcome

一个数据模拟的库,更方便地测试 Egg 应用、插件及自定义 Egg 框架。 @eggjs/mock 拓展自 node_modules/mm,你可以使用所有 mm 包含的 API。

Install

npm i egg-mock --save-dev

Usage

创建测试用例

通过 mm.app 启动应用,可以使用 App 的 API 模拟数据

// test/index.test.js
const path = require('path');
const mm = require('@eggjs/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);
  });
});

使用 mm.app 启动后可以通过 app.agent 访问到 agent 对象。

使用 mm.cluster 启动多进程测试,API 与 mm.app 一致。

应用开发者

应用开发者不需要传入 baseDir,其为当前路径

before(() => {
  app = mm.app({
    framework: path.join(__dirname, '../node_modules/egg'),
  });
  return app.ready();
});

框架开发者

框架开发者需要指定 framework,会将当前路径指定为框架入口

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

插件开发者

在插件目录下执行测试用例时,只要 package.json 中有 eggPlugin.name 字段,就会自动把当前目录加到插件列表中。

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

也可以通过 framework 指定其他框架,比如希望在 aliyun-egg 和 framework-b 同时测试此插件。

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();
  });
});

如果当前目录确实是一个 egg 插件,但是又不想当它是一个插件来测试,可以通过 options.plugin 选项来关闭:

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

API

mm.app(options)

创建一个 mock 的应用。

mm.cluster(options)

创建一个多进程应用,因为是多进程应用,无法获取 worker 的属性,只能通过 supertest 请求。

const mm = require('@eggjs/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)
  });
});

默认会启用覆盖率,因为覆盖率比较慢,可以设置 coverage 关闭

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

mm.env(env)

设置环境变量,主要用于启动阶段,运行阶段可以使用 app.mockEnv。

// 模拟生成环境
mm.env('prod');
mm.app({
  cache: false,
});

具体值见 https://github.com/eggjs/egg-core/blob/master/lib/loader/egg_loader.js#L82

mm.consoleLevel(level)

mock 终端日志打印级别

// 不输出到终端
mm.consoleLevel('NONE');

可选 level 为 DEBUG, INFO, WARN, ERROR, NONE

mm.home(homePath)

模拟操作系统用户目录

mm.restore

还原所有 mock 数据,一般需要结合 afterEach(mm.restore) 使用

options

mm.app 和 mm.cluster 的配置参数

baseDir {String}

当前应用的目录,如果是应用本身的测试可以不填默认为 $CWD。

指定完整路径

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

也支持缩写,找 test/fixtures 目录下的

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

framework {String/Boolean}

指定框架路径

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

对于框架的测试用例,可以指定 true,会自动加载当前路径。

plugin

指定插件的路径,只用于插件测试。设置为 true 会将当前路径设置到插件列表。

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

plugins {Object}

传入插件列表,可以自定义多个插件

cache {Boolean}

是否需要缓存,默认开启。

是通过 baseDir 缓存的,如果不需要可以关闭,但速度会慢。

clean {Boolean}

是否需要清理 log 目录,默认开启。

如果是通过 ava 等并行测试框架进行测试,需要手动在执行测试前进行统一的日志清理,不能通过 mm 来处理,设置 cleanfalse

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

断言指定的字符串记录在指定的日志中。 建议 app.mockLog()app.expectLog() 或者 app.notExpectLog() 配对使用。 单独使用 app.expectLog() 或者 app.notExpectLog() 需要依赖日志的写入速度,在服务器磁盘高 IO 的时候,会出现不稳定的结果。

it('should work', async () => {
  // 将日志记录到内存,用于下面的 expectLog
  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()

请求当前应用 http 服务的辅助工具。

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

更多信息请查看 supertest 的 API 说明。

.unexpectHeader(name)

断言当前请求响应不包含指定 header

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

.expectHeader(name)

断言当前请求响应包含指定 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)

安全的模拟上下文数据,同一用例用多次调用 mockContext 可能会造成 AsyncLocalStorage 污染

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)

模拟请求头

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', async function() {
  app.mockService('user', 'getName', async function(ctx, methodName, args) {
    return 'popomore';
  });
  const ctx = app.mockContext();
  await ctx.service.user.getName();
});

app.mockServiceError(service, methodName, error)

可以模拟一个错误

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

app.mockCsrf()

模拟 csrf,不用传递 token

app.mockCsrf();

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

app.mockHttpclient(url, method, data)

模拟 httpclient 的请求,例如 ctx.curl

app.get('/', async ctx => {
  const ret = await ctx.curl('https://eggjs.org');
  this.body = ret.data.toString();
});

app.mockHttpclient('https://eggjs.org', {
  // 模拟的参数,可以是 buffer / string / json / function
  // 都会转换成 buffer
  // 按照请求时的 options.dataType 来做对应的转换
  data: 'mock egg',
});

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

Bootstrap

我们提供了一个 bootstrap 来减少单测中的重复代码:

const { app, mock, assert } = require('@eggjs/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');
  });
});

我们将会在每个 case 中自定注入 ctx, 可以通过 app.currentContext 来获取当前的 ctx。 并且第一次使用 app.mockContext 会自动复用当前 case 的上下文。

const { app, mock, assert } = require('@eggjs/mock/bootstrap');

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

  it('should reuse ctx', () => {
    const ctx = app.currentContext;
    // 第一次调用会复用上下文
    const mockCtx = app.mockContext();
    assert(ctx === mockCtx);
    // 后续调用会新建上下文
    // 极不建议多次调用 app.mockContext
    // 这会导致上下文污染
    // 建议使用 app.mockContextScope
    const mockCtx2 = app.mockContext();
    assert(ctx !== mockCtx);
  });
});

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

Changelog

6.0.7 (2025-02-08)

Bug Fixes

  • app.mockContext() should return egg context instance (#186) (940f321)

6.0.6 (2025-02-04)

Bug Fixes

6.0.5 (2025-01-02)

Bug Fixes

6.0.4 (2025-01-01)

Bug Fixes

6.0.3 (2024-12-29)

Bug Fixes

6.0.2 (2024-12-29)

Bug Fixes

6.0.1 (2024-12-29)

Bug Fixes

6.0.0 (2024-12-29)

⚠ BREAKING CHANGES

  • drop Node.js < 18.19.0 support

part of https://github.com/eggjs/egg/issues/3644

https://github.com/eggjs/egg/issues/5257

Features

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)