Showing preview only (361K chars total). Download the full file or copy to clipboard to get everything.
Repository: eggjs/egg-mock
Branch: 5.x
Commit: 5ced81620f84
Files: 283
Total size: 291.6 KB
Directory structure:
gitextract_75m1jveo/
├── .eslintrc
├── .github/
│ └── workflows/
│ ├── nodejs.yml
│ ├── pkg.pr.new.yml
│ └── release.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.zh_CN.md
├── app/
│ ├── extend/
│ │ ├── agent.js
│ │ └── application.js
│ └── middleware/
│ └── cluster_app_mock.js
├── app.js
├── bootstrap.d.ts
├── bootstrap.js
├── index.d.ts
├── index.js
├── index.test-d.ts
├── lib/
│ ├── agent_handler.js
│ ├── app.js
│ ├── app_handler.js
│ ├── cluster.js
│ ├── context.js
│ ├── format_options.js
│ ├── http_test.js
│ ├── inject_context.js
│ ├── mock_agent.js
│ ├── mock_custom_loader.js
│ ├── mock_http_server.js
│ ├── mock_httpclient.js
│ ├── parallel/
│ │ ├── agent.js
│ │ ├── agent_register.js
│ │ ├── app.js
│ │ └── util.js
│ ├── prerequire.js
│ ├── request_call_function.js
│ ├── start-cluster
│ ├── supertest.js
│ ├── tmp/
│ │ └── .gitkeep
│ └── utils.js
├── package.json
├── register.js
└── test/
├── agent.test.js
├── app/
│ └── middleware/
│ └── cluster_app_mock.test.js
├── app.test.js
├── app_event.test.js
├── app_proxy.test.js
├── bootstrap-plugin.test.js
├── bootstrap.test.js
├── cluster.test.js
├── ctx.test.js
├── fixtures/
│ ├── agent/
│ │ ├── agent.js
│ │ ├── app.js
│ │ ├── client.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── agent-boot-error/
│ │ ├── agent.js
│ │ └── package.json
│ ├── agent-boot-ready-error/
│ │ ├── agent.js
│ │ └── package.json
│ ├── app/
│ │ ├── app/
│ │ │ └── router.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-boot-error/
│ │ ├── app.js
│ │ └── package.json
│ ├── app-boot-ready-error/
│ │ ├── app.js
│ │ └── package.json
│ ├── app-event/
│ │ ├── agent.js
│ │ ├── app/
│ │ │ └── router.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-fail/
│ │ ├── app/
│ │ │ └── router.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-proxy/
│ │ ├── app/
│ │ │ └── extend/
│ │ │ └── application.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-proxy-ready/
│ │ ├── agent.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-ready-failed/
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── apps/
│ │ ├── app-not-clean/
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ ├── logs/
│ │ │ │ └── keep
│ │ │ └── package.json
│ │ ├── app-throw/
│ │ │ ├── app/
│ │ │ │ └── router.js
│ │ │ ├── config/
│ │ │ │ ├── config.default.js
│ │ │ │ └── config.unittest.js
│ │ │ └── package.json
│ │ ├── barapp/
│ │ │ ├── app/
│ │ │ │ ├── controller/
│ │ │ │ │ └── home.js
│ │ │ │ └── router.js
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ └── package.json
│ │ ├── env-app/
│ │ │ ├── config/
│ │ │ │ ├── config.default.js
│ │ │ │ ├── config.local.js
│ │ │ │ ├── config.prod.js
│ │ │ │ ├── config.test.js
│ │ │ │ └── config.unittest.js
│ │ │ └── package.json
│ │ ├── foo/
│ │ │ ├── app/
│ │ │ │ └── router.js
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ └── package.json
│ │ ├── mock_cookies/
│ │ │ ├── app/
│ │ │ │ └── router.js
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ └── package.json
│ │ ├── mockhome/
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ └── package.json
│ │ ├── no-framework/
│ │ │ ├── config/
│ │ │ │ └── plugin.js
│ │ │ ├── package.json
│ │ │ └── plugin/
│ │ │ └── a/
│ │ │ ├── app/
│ │ │ │ └── extend/
│ │ │ │ └── application.js
│ │ │ └── package.json
│ │ └── parallel-test/
│ │ ├── package.json
│ │ └── test/
│ │ ├── a.test.js
│ │ ├── b.test.js
│ │ └── c.test.js
│ ├── bar/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── index.js
│ │ └── package.json
│ ├── cache/
│ │ ├── config.default.js
│ │ └── package.json
│ ├── chair/
│ │ ├── index.js
│ │ └── package.json
│ ├── create-context-failed/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── custom-loader/
│ │ ├── app/
│ │ │ ├── adapter/
│ │ │ │ └── docker.js
│ │ │ ├── controller/
│ │ │ │ └── user.js
│ │ │ ├── repository/
│ │ │ │ └── user.js
│ │ │ └── router.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── custom_egg/
│ │ └── package.json
│ ├── demo/
│ │ ├── app/
│ │ │ ├── context.js
│ │ │ ├── controller/
│ │ │ │ ├── file.js
│ │ │ │ ├── home.js
│ │ │ │ ├── session.js
│ │ │ │ └── user.js
│ │ │ ├── extend/
│ │ │ │ └── application.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ ├── old.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── demo-async/
│ │ ├── app/
│ │ │ ├── controller/
│ │ │ │ └── home.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── demo_next/
│ │ ├── app/
│ │ │ ├── context.js
│ │ │ ├── controller/
│ │ │ │ ├── file.js
│ │ │ │ ├── home.js
│ │ │ │ ├── session.js
│ │ │ │ └── user.js
│ │ │ ├── extend/
│ │ │ │ └── application.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ ├── old.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── demo_next_h2/
│ │ ├── app/
│ │ │ ├── context.js
│ │ │ ├── controller/
│ │ │ │ ├── file.js
│ │ │ │ ├── home.js
│ │ │ │ ├── session.js
│ │ │ │ └── user.js
│ │ │ ├── extend/
│ │ │ │ └── application.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ ├── old.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── disable-security/
│ │ ├── app/
│ │ │ ├── context.js
│ │ │ ├── controller/
│ │ │ │ ├── home.js
│ │ │ │ └── session.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ ├── old.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ ├── config.js
│ │ │ └── plugin.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── error-framework/
│ │ ├── index.js
│ │ └── package.json
│ ├── failed-app/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── fooPlugin/
│ │ ├── app.js
│ │ ├── config/
│ │ │ ├── config.default.js
│ │ │ └── plugin.js
│ │ └── package.json
│ ├── get-app-failed/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── messenger-binding/
│ │ ├── agent.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── plugin/
│ │ └── package.json
│ ├── plugin-bootstrap/
│ │ ├── package.json
│ │ └── test.js
│ ├── plugin_throw/
│ │ └── package.json
│ ├── request/
│ │ ├── app/
│ │ │ └── router.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── server/
│ │ ├── app.js
│ │ └── package.json
│ ├── setup-app/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ ├── .setup.js
│ │ └── index.test.js
│ ├── tegg-app/
│ │ ├── app/
│ │ │ └── modules/
│ │ │ └── foo/
│ │ │ ├── LogService.ts
│ │ │ └── package.json
│ │ ├── app.js
│ │ ├── config/
│ │ │ ├── config.default.js
│ │ │ └── plugin.js
│ │ ├── package.json
│ │ ├── test/
│ │ │ ├── hooks.test.ts
│ │ │ ├── multi_mock_context.test.ts
│ │ │ ├── tegg.test.ts
│ │ │ └── tegg_context.test.ts
│ │ ├── tsconfig.json
│ │ └── typing.ts
│ ├── test-case-create-context-failed/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── test-case-get-app-failed/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ └── yadan_app/
│ ├── config/
│ │ └── config.default.js
│ └── package.json
├── format_options.test.js
├── index.test.ts
├── inject_ctx.test.js
├── mm.test.js
├── mock_agent_httpclient.test.js
├── mock_cluster_extend.test.js
├── mock_cluster_restore.test.js
├── mock_cluster_without_security_plugin.test.js
├── mock_context.test.js
├── mock_cookies.test.js
├── mock_csrf.test.js
├── mock_custom_loader.test.js
├── mock_env.test.js
├── mock_headers.test.js
├── mock_httpclient.test.js
├── mock_httpclient_next.test.js
├── mock_httpclient_next_h2.test.js
├── mock_request.test.js
├── mock_service.test.js
├── mock_service_async.test.js
├── mock_service_cluster.test.js
├── mock_session.test.js
├── parallel.test.js
├── parallel_hook.test.js
└── tsd.test.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc
================================================
{
"extends": "eslint-config-egg",
"globals": {
"beforeAll": true
}
}
================================================
FILE: .github/workflows/nodejs.yml
================================================
name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
Job:
name: Node.js
uses: node-modules/github-actions/.github/workflows/node-test.yml@master
with:
os: 'ubuntu-latest'
version: '14.18.0, 14, 16, 18, 20, 22'
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
================================================
FILE: .github/workflows/pkg.pr.new.yml
================================================
name: Publish Any Commit
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm install
- name: Build
run: npm run prepublishOnly --if-present
- run: npx pkg-pr-new publish
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
branches: [ master ]
jobs:
release:
name: Node.js
uses: eggjs/github-actions/.github/workflows/node-release.yml@master
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
================================================
FILE: .gitignore
================================================
node_modules/
coverage/
logs/
!test/fixtures/apps/app-not-clean/logs/keep
!test/fixtures/yadan/node_modules
run/
.vscode
.idea
.nyc_output
package-lock.json
================================================
FILE: CHANGELOG.md
================================================
# Changelog
## [5.15.1](https://github.com/eggjs/egg-mock/compare/v5.15.0...v5.15.1) (2024-12-12)
### Bug Fixes
* try to use urllib4 ([#177](https://github.com/eggjs/egg-mock/issues/177)) ([c8551b9](https://github.com/eggjs/egg-mock/commit/c8551b98f044c7315a67f579cc2c1b4f5dde73c4))
## [5.15.0](https://github.com/eggjs/egg-mock/compare/v5.14.0...v5.15.0) (2024-12-10)
### Features
* use @eggjs/utils ([#176](https://github.com/eggjs/egg-mock/issues/176)) ([48000cb](https://github.com/eggjs/egg-mock/commit/48000cb468fd25ac258d728ecc9afca21a8f6284))
## [5.14.0](https://github.com/eggjs/egg-mock/compare/v5.13.0...v5.14.0) (2024-12-09)
### Features
* detect-port@2, is-type-of@2, get-ready@3 ([#175](https://github.com/eggjs/egg-mock/issues/175)) ([0364af8](https://github.com/eggjs/egg-mock/commit/0364af8d87237bc6c08e2f9306945daa1d9144c9))
## [5.13.0](https://github.com/eggjs/egg-mock/compare/v5.12.5...v5.13.0) (2024-12-07)
### Features
* mv urllib to peerDependencies ([#174](https://github.com/eggjs/egg-mock/issues/174)) ([df7dc48](https://github.com/eggjs/egg-mock/commit/df7dc48be38f7f323f91213aa3ce3bd5e7879a58))
## [5.12.5](https://github.com/eggjs/egg-mock/compare/v5.12.4...v5.12.5) (2024-07-05)
### Bug Fixes
* should run restore in the current event loop ([#172](https://github.com/eggjs/egg-mock/issues/172)) ([1f9fc01](https://github.com/eggjs/egg-mock/commit/1f9fc0179ac524cbeb0532b92783233c0274ce71))
## [5.12.4](https://github.com/eggjs/egg-mock/compare/v5.12.3...v5.12.4) (2024-07-04)
### Bug Fixes
* should reset agent on restore ([#171](https://github.com/eggjs/egg-mock/issues/171)) ([088ac41](https://github.com/eggjs/egg-mock/commit/088ac41d96daecf62c544ca954812d3721ac06cc))
## [5.12.3](https://github.com/eggjs/egg-mock/compare/v5.12.2...v5.12.3) (2024-07-02)
### Bug Fixes
* don't close used mock agent ([#170](https://github.com/eggjs/egg-mock/issues/170)) ([3e7a504](https://github.com/eggjs/egg-mock/commit/3e7a5044e3a687c8accbfc9f8a60c469bf4fdad6))
## [5.12.2](https://github.com/eggjs/egg-mock/compare/v5.12.1...v5.12.2) (2024-07-02)
### Bug Fixes
* export mockHttpClient types ([#169](https://github.com/eggjs/egg-mock/issues/169)) ([ddab25f](https://github.com/eggjs/egg-mock/commit/ddab25f1b06e1e513c2dd523bf7d773970d37031))
## [5.12.1](https://github.com/eggjs/egg-mock/compare/v5.12.0...v5.12.1) (2024-07-02)
### Bug Fixes
* support httpclient mock on allowH2 = true ([#168](https://github.com/eggjs/egg-mock/issues/168)) ([3a434bb](https://github.com/eggjs/egg-mock/commit/3a434bb6a90c98b957b6d92e059c09297bf7cf18))
## [5.12.0](https://github.com/eggjs/egg-mock/compare/v5.11.0...v5.12.0) (2024-06-02)
### Features
* change backgroundTasksFinished method from private to public ([#163](https://github.com/eggjs/egg-mock/issues/163)) ([86b4d45](https://github.com/eggjs/egg-mock/commit/86b4d452f0e5e851e8fd550a74f244c91de5c093))
## [5.11.0](https://github.com/eggjs/egg-mock/compare/v5.10.9...v5.11.0) (2024-06-02)
### Features
* use egg-logger@3 and sdk-base@4 ([#167](https://github.com/eggjs/egg-mock/issues/167)) ([e02e72e](https://github.com/eggjs/egg-mock/commit/e02e72ef561ae029be3671ebf2a8e37ad06dc2d1))
## [5.10.9](https://github.com/eggjs/egg-mock/compare/v5.10.8...v5.10.9) (2023-11-08)
### Bug Fixes
* allow to call mockHttpclient multi times ([#165](https://github.com/eggjs/egg-mock/issues/165)) ([370e42d](https://github.com/eggjs/egg-mock/commit/370e42d777d89dcfde1773db6404284439b38725))
## [5.10.8](https://github.com/eggjs/egg-mock/compare/v5.10.7...v5.10.8) (2023-06-21)
### Bug Fixes
* fix mocha failed title for inject_ctx ([#162](https://github.com/eggjs/egg-mock/issues/162)) ([f6f59ac](https://github.com/eggjs/egg-mock/commit/f6f59ac48789fb2c81dfd3025b626c2ed4090a36))
## [5.10.7](https://github.com/eggjs/egg-mock/compare/v5.10.6...v5.10.7) (2023-05-29)
### Bug Fixes
* set types to index.d.ts ([#161](https://github.com/eggjs/egg-mock/issues/161)) ([7de47a1](https://github.com/eggjs/egg-mock/commit/7de47a1e6bb8d4d003b93c130d1e08c7ac0c8bf7))
## [5.10.6](https://github.com/eggjs/egg-mock/compare/v5.10.5...v5.10.6) (2023-02-22)
### Bug Fixes
* disable app close on parallel ([#160](https://github.com/eggjs/egg-mock/issues/160)) ([5a08d33](https://github.com/eggjs/egg-mock/commit/5a08d33ffcbc047ef374a5ab99bee00ad5675808))
## [5.10.5](https://github.com/eggjs/egg-mock/compare/v5.10.4...v5.10.5) (2023-02-16)
### Bug Fixes
* should close app on afterAll hook ([#158](https://github.com/eggjs/egg-mock/issues/158)) ([081b157](https://github.com/eggjs/egg-mock/commit/081b1574c31cfe274083b21a1e11bc81304ab1d5))
## [5.10.4](https://github.com/eggjs/egg-mock/compare/v5.10.3...v5.10.4) (2023-01-31)
### Bug Fixes
* use symbol to access suite app ([#156](https://github.com/eggjs/egg-mock/issues/156)) ([a130dd3](https://github.com/eggjs/egg-mock/commit/a130dd307258df540b65b6d445b56681f69d9232))
## [5.10.3](https://github.com/eggjs/egg-mock/compare/v5.10.2...v5.10.3) (2023-01-30)
### Bug Fixes
* inject failed should make suite/test failed ([#154](https://github.com/eggjs/egg-mock/issues/154)) ([f9f2d4c](https://github.com/eggjs/egg-mock/commit/f9f2d4c5184b2fd2a60485d9333bfefb2c42fabb))
## [5.10.2](https://github.com/eggjs/egg-mock/compare/v5.10.1...v5.10.2) (2023-01-30)
### Bug Fixes
* make sure app ready on parallel mode ([#155](https://github.com/eggjs/egg-mock/issues/155)) ([83c600e](https://github.com/eggjs/egg-mock/commit/83c600e8cb8139a232f1066c2925562574102dbe))
## [5.10.1](https://github.com/eggjs/egg-mock/compare/v5.10.0...v5.10.1) (2023-01-29)
### Bug Fixes
* fix mockContext with headers ([#153](https://github.com/eggjs/egg-mock/issues/153)) ([5e3e816](https://github.com/eggjs/egg-mock/commit/5e3e816395d8be37548d4bb72c3e3dc2d098bee1))
## [5.10.0](https://github.com/eggjs/egg-mock/compare/v5.9.4...v5.10.0) (2023-01-28)
### Features
* add default ua egg-mock/${version} ([#151](https://github.com/eggjs/egg-mock/issues/151)) ([ccb28f5](https://github.com/eggjs/egg-mock/commit/ccb28f5a99148528459f1f8b120254f3feb64561))
* impl setGetAppCallback ([#152](https://github.com/eggjs/egg-mock/issues/152)) ([b7d902c](https://github.com/eggjs/egg-mock/commit/b7d902cf990ee90181f24e9722f42560858118eb))
## [5.9.4](https://github.com/eggjs/egg-mock/compare/v5.9.3...v5.9.4) (2023-01-18)
### Bug Fixes
* use originalUrl to check mock call function request ([#149](https://github.com/eggjs/egg-mock/issues/149)) ([abe1c07](https://github.com/eggjs/egg-mock/commit/abe1c07a2abb4b98c37a34725e4917caafe6dc7e))
## [5.9.3](https://github.com/eggjs/egg-mock/compare/v5.9.2...v5.9.3) (2023-01-18)
### Bug Fixes
* every it should has self ctx ([#150](https://github.com/eggjs/egg-mock/issues/150)) ([bf33c1c](https://github.com/eggjs/egg-mock/commit/bf33c1cbde00b0f10d49184bda305c2c98a58401))
## [5.9.2](https://github.com/eggjs/egg-mock/compare/v5.9.1...v5.9.2) (2023-01-17)
### Bug Fixes
* mocha should be peer deps ([#148](https://github.com/eggjs/egg-mock/issues/148)) ([9a5fcca](https://github.com/eggjs/egg-mock/commit/9a5fcca1ff19f2bc7d74a8122becc1bf0ddfe89d))
## [5.8.4](https://github.com/eggjs/egg-mock/compare/v5.8.3...v5.8.4) (2023-01-12)
### Bug Fixes
* only await app ready when app exists ([#145](https://github.com/eggjs/egg-mock/issues/145)) ([f4ed458](https://github.com/eggjs/egg-mock/commit/f4ed458441449da70fd4108747377b7890dc08fb))
## [5.8.3](https://github.com/eggjs/egg-mock/compare/v5.8.2...v5.8.3) (2023-01-11)
### Bug Fixes
* app should wait for agent ready on parallel mode ([#144](https://github.com/eggjs/egg-mock/issues/144)) ([205e836](https://github.com/eggjs/egg-mock/commit/205e836ba11a869da208c441a9b90edd6e61b3b1))
## [5.8.2](https://github.com/eggjs/egg-mock/compare/v5.8.1...v5.8.2) (2023-01-10)
### Bug Fixes
* ignore bootstrap error on non egg project ([#142](https://github.com/eggjs/egg-mock/issues/142)) ([880c282](https://github.com/eggjs/egg-mock/commit/880c282481024005456074a123b4b1f185971f4c))
## [5.8.1](https://github.com/eggjs/egg-mock/compare/v5.8.0...v5.8.1) (2023-01-09)
### Bug Fixes
* add register.js to files ([#141](https://github.com/eggjs/egg-mock/issues/141)) ([a87e801](https://github.com/eggjs/egg-mock/commit/a87e8019724dbb2401bd41ccf95be26c571e8e8f))
## [5.8.0](https://github.com/eggjs/egg-mock/compare/v5.7.1...v5.8.0) (2023-01-09)
### Features
* use mocha global hook to register before/after ([#140](https://github.com/eggjs/egg-mock/issues/140)) ([9ef65de](https://github.com/eggjs/egg-mock/commit/9ef65de3382c15c5fdeff2e8d0b14eed8144a41b))
## [5.7.1](https://github.com/eggjs/egg-mock/compare/v5.7.0...v5.7.1) (2023-01-07)
### Bug Fixes
* should add egg to peerDependencies ([#139](https://github.com/eggjs/egg-mock/issues/139)) ([2134fc7](https://github.com/eggjs/egg-mock/commit/2134fc73661e4c2de433aceda2ea45811c8bff8b))
## [5.7.0](https://github.com/eggjs/egg-mock/compare/v5.6.0...v5.7.0) (2023-01-03)
### Features
* remove power-assert ([#138](https://github.com/eggjs/egg-mock/issues/138)) ([0c9fad2](https://github.com/eggjs/egg-mock/commit/0c9fad2f7a6f739080f2b996d8f6bb98852af12a))
## [5.6.0](https://github.com/eggjs/egg-mock/compare/v5.5.0...v5.6.0) (2023-01-03)
### Features
* upgrade globby to v11 ([#137](https://github.com/eggjs/egg-mock/issues/137)) ([b0af3eb](https://github.com/eggjs/egg-mock/commit/b0af3eb471a394448236e4cb18863e60218e0d2a))
## [5.5.0](https://github.com/eggjs/egg-mock/compare/v5.4.0...v5.5.0) (2022-12-28)
### Features
* add mockContextScope ([#136](https://github.com/eggjs/egg-mock/issues/136)) ([9db9afa](https://github.com/eggjs/egg-mock/commit/9db9afaadfb73a58d03b3cbdbd0c8c6515e6578a))
---
5.4.0 / 2022-12-14
==================
**features**
* [[`0bd71bc`](http://github.com/eggjs/egg-mock/commit/0bd71bc732b430f679854cceb5017238aca67f38)] - 📦 NEW: Allow restore mockAgent only (#134) (fengmk2 <<fengmk2@gmail.com>>)
5.3.0 / 2022-12-09
==================
**features**
* [[`6608f01`](http://github.com/eggjs/egg-mock/commit/6608f01983b6891fad2eea758e426bb205dff117)] - 📦 NEW: mock context support ctxStorage (#133) (fengmk2 <<fengmk2@gmail.com>>)
5.2.1 / 2022-11-11
==================
**fixes**
* [[`18c366d`](http://github.com/eggjs/egg-mock/commit/18c366d4d8f110e8b5e166bb4109be6659f59dd2)] - fix: use global hook for register global hook (#132) (killa <<killa123@126.com>>)
5.2.0 / 2022-11-08
==================
**features**
* [[`209c921`](http://github.com/eggjs/egg-mock/commit/209c921cd07eeb541793d5eb28a4982c891ef337)] - feat: add EGG_FRAMEWORK for bootstrap custom framework (#131) (killa <<killa123@126.com>>)
5.1.0 / 2022-11-04
==================
**features**
* [[`22f508c`](http://github.com/eggjs/egg-mock/commit/22f508cba2f6330172db89efde3a678ed35c5258)] - feat: impl parallel app for mocha parallel mode (#130) (killa <<killa123@126.com>>)
5.0.2 / 2022-10-09
==================
**fixes**
* [[`299f7ec`](http://github.com/eggjs/egg-mock/commit/299f7ecc7314737c182c1745fce0d32c61cd657d)] - 🐛 FIX: Should use urllib-next package (#129) (fengmk2 <<fengmk2@gmail.com>>)
**others**
* [[`17a6713`](http://github.com/eggjs/egg-mock/commit/17a6713663555f55832c12fa12c68803a59aa925)] - 🤖 TEST: Add httpclient streaming mocking (#128) (fengmk2 <<fengmk2@gmail.com>>)
5.0.1 / 2022-09-29
==================
**features**
* [[`ae766ff`](http://github.com/eggjs/egg-mock/commit/ae766ff582a3e14a28b97e15bad5a56efcb542bc)] - 👌 IMPROVE: Mock httpclient support delay ms and repeat times (#127) (fengmk2 <<fengmk2@gmail.com>>)
5.0.0 / 2022-09-29
==================
**features**
* [[`60658ec`](http://github.com/eggjs/egg-mock/commit/60658ecae4a16ac1e52dc3238c279a61262f4620)] - 📦 NEW: [BREAKING] Support egg 3.0 (#126) (fengmk2 <<fengmk2@gmail.com>>)
4.2.1 / 2022-05-17
==================
**features**
* [[`983e610`](http://github.com/eggjs/egg-mock/commit/983e6106b3047f3c0b8d1871fecf4b851cb3000a)] - feat: allow other envtype (#125) (吖猩 <<whx89768@alibaba-inc.com>>)
**others**
* [[`bb9cb79`](http://github.com/eggjs/egg-mock/commit/bb9cb79dbd3d8999cc887d1f0ea952b5df449086)] - 📖 DOC: Change ci status badge (fengmk2 <<fengmk2@gmail.com>>)
* [[`cd1f2db`](http://github.com/eggjs/egg-mock/commit/cd1f2dbd08683e60b31b83e3406c32a823124704)] - 📖 DOC: Update contributors (fengmk2 <<fengmk2@gmail.com>>)
* [[`74c0d8f`](http://github.com/eggjs/egg-mock/commit/74c0d8f5a9532fa9e3b3f1c29ad27b59d46ea984)] - Create codeql-analysis.yml (fengmk2 <<fengmk2@gmail.com>>)
* [[`6bcc866`](http://github.com/eggjs/egg-mock/commit/6bcc8660a94c761dbdcee0a09bcd6d06e8441f49)] - 🤖 TEST: Fix assert cases (#124) (fengmk2 <<fengmk2@gmail.com>>)
4.2.0 / 2021-12-17
==================
**features**
* [[`b45ad40`](http://github.com/eggjs/egg-mock/commit/b45ad40dd572977986cd86220f090d28c1268b70)] - feat: add mockLog, expectLog to type define (#121) (fengmk2 <<fengmk2@gmail.com>>)
4.1.0 / 2021-04-05
==================
**features**
* [[`ce6ecde`](https://github.com/eggjs/egg-mock.git/commit/ce6ecde700a81ce986347834dbd2dc2d48217f88)] - feat: add consoleLogger error when mockApp init error (mansonchor.github.com <<mansonchor1987@gmail.com>>)
**others**
* [[`e7c73e3`](https://github.com/eggjs/egg-mock.git/commit/e7c73e37814b6c9041f37bbcd92b3bb7c35758b3)] - build: remove node@6 (dead-horse <<dead_horse@qq.com>>)
4.0.1 / 2020-08-19
==================
**features**
* [[`d5e584e`](http://github.com/eggjs/egg-mock/commit/d5e584e769dd348bc87a99a90f0a6003dfc7a4cf)] - feat: httpclient support mock async function (#117) (Yiyu He <<dead_horse@qq.com>>)
4.0.0 / 2020-03-01
==================
**features**
* [[`c39109f`](http://github.com/eggjs/egg-mock/commit/c39109faa0eff01d8597c3988c04459c3520f309)] - feat: upgrade mm@3 (#116) (Yiyu He <<dead_horse@qq.com>>)
3.25.1 / 2020-01-17
==================
**fixes**
* [[`51ef091`](http://github.com/eggjs/egg-mock/commit/51ef091cbb06ae74ff7f9591e3071db648ba5346)] - fix: backgroundTasksFinished ensure all tasks finished (#115) (Yiyu He <<dead_horse@qq.com>>)
3.25.0 / 2019-12-12
==================
**features**
* [[`4c31c9e`](http://github.com/eggjs/egg-mock/commit/4c31c9e2917eea449e2afddf96fc8d2aabe6ad5e)] - feat: support init hook before mock app init (#109) (TZ | 天猪 <<atian25@qq.com>>)
**fixes**
* [[`cbab52a`](http://github.com/eggjs/egg-mock/commit/cbab52a697e6e47abd48ce45320b7c40a0463c12)] - fix: enable sendRandom() method in unittest (#114) (GoodMeowing <<36814673+GoodMeowing@users.noreply.github.com>>)
3.24.2 / 2019-11-07
==================
**fixes**
* [[`3bf5ded`](http://github.com/eggjs/egg-mock/commit/3bf5ded501608f2b5b3199d8b3d0ca0329dd9df7)] - fix: mockLog don't read file (#113) (Yiyu He <<dead_horse@qq.com>>)
3.24.1 / 2019-09-30
==================
**fixes**
* [[`bd305d2`](http://github.com/eggjs/egg-mock/commit/bd305d21bd54395e597f3fce06758fcbb99ba43f)] - fix: single mode will call app.agent.close (#108) (TZ | 天猪 <<atian25@qq.com>>)
3.24.0 / 2019-09-26
==================
**features**
* [[`315e685`](http://github.com/eggjs/egg-mock/commit/315e685d2059ec61e62e9109da8b58f9bf5552cd)] - feat: support app.notExpectLog() (#107) (fengmk2 <<fengmk2@gmail.com>>)
3.23.2 / 2019-09-10
==================
**fixes**
* [[`e494325`](http://github.com/eggjs/egg-mock/commit/e494325562b84876a96062fd061ab4f8c7787a2e)] - fix: mockHttpclient with multi-request (#106) (吖猩 <<whx89768@alibaba-inc.com>>)
* [[`d836536`](http://github.com/eggjs/egg-mock/commit/d8365368e2339f25874a7dfc1c573249ae841e8f)] - fix: fix httpRequest function signature (#105) (Colin Cheng <<zbinlin@gmail.com>>)
3.23.1 / 2019-05-20
==================
**fixes**
* [[`6be0c43`](http://github.com/eggjs/egg-mock/commit/6be0c431ee1fd651c4f0bb6f433d7c4444b74708)] - fix: rimraf (#104) (TZ | 天猪 <<atian25@qq.com>>)
3.23.0 / 2019-05-20
==================
**features**
* [[`9ada7f0`](http://github.com/eggjs/egg-mock/commit/9ada7f004def359a0b17f3824cea946abe4ed1f2)] - feat: mockHttpclient support fn (#103) (TZ | 天猪 <<atian25@qq.com>>)
3.22.4 / 2019-05-06
==================
**fixes**
* [[`478581a`](http://github.com/eggjs/egg-mock/commit/478581a7851d19286c4e689af421a70cae27d26d)] - fix: remove egg-core deps (#101) (TZ | 天猪 <<atian25@qq.com>>)
3.22.3 / 2019-05-06
==================
**fixes**
* [[`6174f9b`](http://github.com/eggjs/egg-mock/commit/6174f9b37698399785b99e86f2f45630f78a084f)] - fix: throw error when an egg plugin test is using bootstrap (#100) (TZ | 天猪 <<atian25@qq.com>>)
3.22.2 / 2019-04-10
==================
**fixes**
* [[`a68ca65`](http://github.com/eggjs/egg-mock/commit/a68ca6549428e6c4dc886231d7c6b7fbefab46c6)] - fix: should emit server (#98) (TZ | 天猪 <<atian25@qq.com>>)
3.22.1 / 2019-03-12
==================
**fixes**
* [[`3f73bad`](http://github.com/eggjs/egg-mock/commit/3f73bad59aa8acbb14399a914d31b8eb348ff493)] - fix: d.ts typo (#97) (TZ | 天猪 <<atian25@qq.com>>)
3.22.0 / 2019-03-11
==================
**features**
* [[`81ed542`](http://github.com/eggjs/egg-mock/commit/81ed5427853067d84901c1848e630a8002ecfcf0)] - feat: add mock API for customLoader (#95) (Haoliang Gao <<sakura9515@gmail.com>>)
**fixes**
* [[`58d0b32`](http://github.com/eggjs/egg-mock/commit/58d0b32a5851e4cd31492fe0e85c0e81336b6d04)] - fix: remove nonexistent type and correct typing (#96) (Sinux <<askb@me.com>>)
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**
* [[`4b5dbb5`](http://github.com/eggjs/egg-mock/commit/4b5dbb512bf8f598d5ea5361c58ae9d40d528ff8)] - fix: add app.mockLog() to improve app.expectLog() more stable (#87) (fengmk2 <<fengmk2@gmail.com>>)
**others**
* [[`a64db33`](http://github.com/eggjs/egg-mock/commit/a64db33d2ee68a76f7c41303e79e37099f33b373)] - deps: add egg-logger dependency (#88) (fengmk2 <<fengmk2@gmail.com>>)
3.20.0 / 2018-08-30
==================
**features**
* [[`283eef3`](http://github.com/eggjs/egg-mock/commit/283eef3a4f1b0bcd90cc0d6bcf6de9fe136d8503)] - feat: add `app.agent.mockHttpclient()` for agent (#82) (limerick <<guods2015@gmail.com>>)
3.19.7 / 2018-08-28
==================
**fixes**
* [[`cc6b976`](http://github.com/eggjs/egg-mock/commit/cc6b976a66103dca44428e9ca4cf6e8d18b8323b)] - fix: app.messenger.broadcast send to self (君羽 <<ImHype@users.noreply.github.com>>)
3.19.6 / 2018-08-24
==================
**fixes**
* [[`00fb82e`](http://github.com/eggjs/egg-mock/commit/00fb82eac8114f0be1a97421ea270947ea7b5efd)] - fix: fix declaration merging error (#86) (吖猩 <<whxaxes@qq.com>>)
3.19.5 / 2018-08-24
==================
**fixes**
* [[`1635a90`](http://github.com/eggjs/egg-mock/commit/1635a9098d16df4ba4195d2e289476471bf96cb2)] - fix: show expectLog last 500 words on assert error (#85) (fengmk2 <<fengmk2@gmail.com>>)
3.19.4 / 2018-08-24
===================
* feat: .d.ts 新增继承自 mm 的 api (#81)
3.19.3 / 2018-08-16
==================
**fixes**
* [[`c91bf93`](http://github.com/eggjs/egg-mock/commit/c91bf93e792c788c4cdd7cf786a45fc2ecb4511d)] - fix: allow egg-core module missing (#83) (fengmk2 <<fengmk2@gmail.com>>)
3.19.2 / 2018-08-07
==================
**fixes**
* [[`1710f7f`](http://github.com/eggjs/egg-mock/commit/1710f7fcfdbd8709d6b4c50817ab0c214c525378)] - fix: put mock restore at the end (#80) (fengmk2 <<fengmk2@gmail.com>>)
3.19.1 / 2018-08-07
==================
**fixes**
* [[`db3cb11`](http://github.com/eggjs/egg-mock/commit/db3cb11a97ec6bdb3a70222a459241ffc3cc2c47)] - fix: make sure backgroundTasksFinished() return promise (#79) (fengmk2 <<fengmk2@gmail.com>>)
3.19.0 / 2018-08-06
==================
**features**
* [[`ab5a47e`](https://github.com/eggjs/egg-mock.git/commit/ab5a47e12f1fea4300a44ef19aa4ba300574d18a)] - feat: should wait for background task finish on afterEach (#78) (fengmk2 <<fengmk2@gmail.com>>)
3.18.0 / 2018-08-03
==================
**features**
* [[`f25c50a`](http://github.com/eggjs/egg-mock/commit/f25c50a24433e251e5c9f905170cea87e3ac93e6)] - feat: add `app.expectLog()` for app and cluster (#77) (fengmk2 <<fengmk2@gmail.com>>)
**others**
* [[`ffb1187`](http://github.com/eggjs/egg-mock/commit/ffb1187aab11bc544c4bc6c5921ca0fba28e621f)] - chore: improve tsd and add bootstrap.d.ts (#76) (SuperEVO <<zhang740@qq.com>>)
3.17.3 / 2018-07-14
===================
* types: add bootstrap.d.ts (#75)
3.17.2 / 2018-05-21
==================
**others**
* [[`62c3dfa`](http://github.com/eggjs/egg-mock/commit/62c3dfa517b94c56c35fed8af8d9aad29e7c38d4)] - refactor: middleware use promise-based style (#74) (Haoliang Gao <<sakura9515@gmail.com>>)
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**
* [[`3fbf862`](http://github.com/eggjs/egg-mock/commit/3fbf86232ee3c8e4944c8072e127c0f1ede1d26b)] - fix: mockSession save (#68) (TZ | 天猪 <<atian25@qq.com>>)
3.15.0 / 2018-03-08
==================
**features**
* [[`9857065`](http://github.com/eggjs/egg-mock/commit/985706518e9ab8be155f285490484e5a304833fc)] - feat: add unexpectHeader() and expectHeader() (#67) (fengmk2 <<fengmk2@gmail.com>>)
* [[`f1820d7`](http://github.com/eggjs/egg-mock/commit/f1820d70f2e266d4b18fb7062976b4c14952a16f)] - feat: mm.app() support server event (#65) (fengmk2 <<fengmk2@gmail.com>>)
3.14.1 / 2018-02-28
==================
**fixes**
* [[`d38d615`](http://github.com/eggjs/egg-mock/commit/d38d615c3f9bc79eb09c6864ab9d5833a50d029a)] - fix: mockUrl accepts RegExp (#64) (Brick <<brick.c.yang@gmail.com>>)
**others**
* [[`23c1075`](http://github.com/eggjs/egg-mock/commit/23c1075f5aaaa866b0243061d0eadf21ce67d382)] - test: add post with multipart file test cases (#63) (fengmk2 <<fengmk2@gmail.com>>)
3.14.0 / 2017-12-12
==================
**others**
* [[`be9bcd2`](http://github.com/eggjs/egg-mock/commit/be9bcd22c91044b0efdbc3db6b8109cf625002b1)] - refactor: modify d.ts and support bootstrap (Eward Song <<eward.song@gmail.com>>)
3.13.1 / 2017-10-17
==================
**fixes**
* [[`9d071b2`](http://github.com/eggjs/egg-mock/commit/9d071b28c5ef341ee63ccb06f00f724922c698b2)] - fix: support mock the same property multiple times (#61) (Yiyu He <<dead_horse@qq.com>>)
3.13.0 / 2017-10-10
==================
**features**
* [[`30ca0c9`](http://github.com/eggjs/egg-mock/commit/30ca0c980f3ee8b1f60f5213f0768fe5eeaaf49a)] - feat: port can be customized (#60) (Haoliang Gao <<sakura9515@gmail.com>>)
3.12.2 / 2017-09-22
==================
**fixes**
* [[`5935564`](http://github.com/eggjs/egg-mock/commit/5935564d1e649f8702c0f3f79e67efde10717542)] - fix: missing methods package (dainli <<dainli@outlook.com>>)
**others**
* [[`e7f518a`](http://github.com/eggjs/egg-mock/commit/e7f518a92e1686973bea557eb0a21f1d293ab0b4)] - fix(mockHttpclient): should use the copy of mockResult (#58) (Haoliang Gao <<sakura9515@gmail.com>>)
* [new tag] 3.12.1 -> 3.12.1
3.12.1 / 2017-09-13
==================
**others**
* [[`e7f518a`](http://github.com/eggjs/egg-mock/commit/e7f518a92e1686973bea557eb0a21f1d293ab0b4)] - fix(mockHttpclient): should use the copy of mockResult (#58) (Haoliang Gao <<sakura9515@gmail.com>>)
3.12.0 / 2017-09-12
==================
**others**
* [[`25a0e28`](http://github.com/eggjs/egg-mock/commit/25a0e28e85209ec08a593b38cd434ed389ef8887)] - feat(mockHttpclient): use Regular Expression for matching url (#57) (Haoliang Gao <<sakura9515@gmail.com>>)
3.11.0 / 2017-09-11
==================
**features**
* [[`f1a08a6`](http://github.com/eggjs/egg-mock/commit/f1a08a654a08313c0848828ee9051f8bf174fc6a)] - feat: support httpRequest().get(routerName) (#56) (fengmk2 <<fengmk2@gmail.com>>)
3.10.0 / 2017-08-30
==================
**features**
* [[`f3654df`](http://github.com/eggjs/egg-mock/commit/f3654df99d4bee2ea0ee1ef580af7af66f21255d)] - feat: base promise to support async function (#55) (Yiyu He <<dead_horse@qq.com>>)
3.9.1 / 2017-08-14
==================
**fixes**
* [[`d6cafaa`](http://github.com/eggjs/egg-mock/commit/d6cafaa531d9bbcc0fc987e7d6fdefd6a515e785)] - fix: fix agent type after ready (#54) (zōng yǔ <<gxcsoccer@users.noreply.github.com>>)
3.9.0 / 2017-08-02
==================
**features**
* [[`9e1642c`](http://github.com/eggjs/egg-mock/commit/9e1642c7fc569d3cc4a73c9ede6511a18cca6fc5)] - feat: add bootstrap (#53) (Yiyu He <<dead-horse@users.noreply.github.com>>)
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)
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017-present Alibaba Group Holding Limited and other contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# egg-mock
[![NPM version][npm-image]][npm-url]
[](https://github.com/eggjs/egg-mock/actions/workflows/nodejs.yml)
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url]
[npm-image]: https://img.shields.io/npm/v/egg-mock.svg?style=flat-square
[npm-url]: https://npmjs.org/package/egg-mock
[codecov-image]: https://codecov.io/github/eggjs/egg-mock/coverage.svg?branch=master
[codecov-url]: https://codecov.io/github/eggjs/egg-mock?branch=master
[download-image]: https://img.shields.io/npm/dm/egg-mock.svg?style=flat-square
[download-url]: https://npmjs.org/package/egg-mock
Mock library for testing Egg applications, plugins and custom Egg frameworks with ease. `egg-mock` inherits all APIs from [node_modules/mm](https://github.com/node-modules/mm), offering more flexibility.
## Install
```bash
$ npm i egg-mock --save-dev
```
## Usage
### Create testcase
Launch a mock server with `mm.app`
```js
// 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.
```js
before(() => {
app = mm.app();
return app.ready();
});
```
### Test Framework
framework is optional, it's `node_modules/egg` by default.
```js
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.
```js
before(() => {
app = mm.app({
baseDir: 'apps/demo',
});
return app.ready();
});
```
You can also test the plugin in different framework, e.g. test [aliyun-egg](https://github.com/eggjs/aliyun-egg) and framework-b in one plugin.
```js
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`.
```js
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`.
```js
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.
```js
mm.cluster({
coverage: false,
});
```
### mm.env(env)
Mock env when starting
```js
// 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
```js
// 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()`.
```js
mm.app({
baseDir: path.join(__dirname, 'fixtures/apps/demo'),
})
```
You can use a string based on `$CWD/test/fixtures` for short
```js
mm.app({
baseDir: 'apps/demo',
})
```
#### framework {String/Boolean}
The directory of framework
```js
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.
```js
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.
```js
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.
```js
it('should work', () => {
return app.httpRequest()
.get('/')
.expect('hello world')
.expect(200);
});
```
See [supertest](https://github.com/visionmedia/supertest) to get more APIs.
#### .unexpectHeader(name)
Assert current response not contains the specified header
```js
it('should work', () => {
return app.httpRequest()
.get('/')
.unexpectHeader('set-cookie')
.expect(200);
});
```
#### .expectHeader(name)
Assert current response contains the specified header
```js
it('should work', () => {
return app.httpRequest()
.get('/')
.expectHeader('set-cookie')
.expect(200);
});
```
### app.mockContext(options)
```js
const ctx = app.mockContext({
user: {
name: 'Jason'
}
});
console.log(ctx.user.name); // Jason
```
### app.mockContextScope(fn, options)
```js
await app.mockContextScope(async ctx => {
console.log(ctx.user.name); // Jason
}, {
user: {
name: 'Jason'
}
});
```
### app.mockCookies(data)
```js
app.mockCookies({
foo: 'bar'
});
const ctx = app.mockContext();
console.log(ctx.getCookie('foo'));
```
### app.mockHeaders(data)
Mock request header
### app.mockSession(data)
```js
app.mockSession({
foo: 'bar'
});
const ctx = app.mockContext();
console.log(ctx.session.foo);
```
### app.mockService(service, methodName, fn)
```js
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
```js
app.mockServiceError('user', 'home', new Error('mock error'));
```
### app.mockCsrf()
```js
app.mockCsrf();
return app.httpRequest()
.post('/login')
.expect(302);
```
### app.mockHttpclient(url, method, data)
Mock httpclient request, e.g.: `ctx.curl`
```js
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.
```js
app.mockHttpclient(/\/users\/[a-z]$/i, {
data: {
name: 'egg',
},
});
```
You can alse mock agent.httpclient
```js
app.agent.mockHttpclient('https://eggjs.org', {
data: {
name: 'egg',
},
});
```
## Bootstrap
We also provide a bootstrap file for applications' unit test to reduce duplicated code:
```js
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`.
```js
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.
```js
// 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](https://github.com/eggjs/egg/issues).
## License
[MIT](LICENSE)
## Contributors
[](https://github.com/eggjs/egg-mock/graphs/contributors)
Made with [contributors-img](https://contrib.rocks).
================================================
FILE: README.zh_CN.md
================================================
# egg-mock
[![NPM version][npm-image]][npm-url]
[](https://github.com/eggjs/egg-mock/actions/workflows/nodejs.yml)
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url]
[npm-image]: https://img.shields.io/npm/v/egg-mock.svg?style=flat-square
[npm-url]: https://npmjs.org/package/egg-mock
[codecov-image]: https://codecov.io/github/eggjs/egg-mock/coverage.svg?branch=master
[codecov-url]: https://codecov.io/github/eggjs/egg-mock?branch=master
[download-image]: https://img.shields.io/npm/dm/egg-mock.svg?style=flat-square
[download-url]: https://npmjs.org/package/egg-mock
一个数据模拟的库,更方便地测试 Egg 应用、插件及自定义 Egg 框架。`egg-mock` 拓展自 [node_modules/mm](https://github.com/node-modules/mm),你可以使用所有 `mm` 包含的 API。
## Install
```bash
$ npm i egg-mock --save-dev
```
## Usage
### 创建测试用例
通过 `mm.app` 启动应用,可以使用 App 的 API 模拟数据
```js
// 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'
customEgg: path.join(__dirname, '../node_modules/egg'),
});
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,其为当前路径
```js
before(() => {
app = mm.app({
customEgg: path.join(__dirname, '../node_modules/egg'),
});
return app.ready();
});
```
### 框架开发者
框架开发者需要指定 customEgg,会将当前路径指定为框架入口
```js
before(() => {
app = mm.app({
baseDir: 'apps/demo',
customEgg: true,
});
return app.ready();
});
```
### 插件开发者
在插件目录下执行测试用例时,只要 `package.json` 中有 `eggPlugin.name` 字段,就会自动把当前目录加到插件列表中。
```js
before(() => {
app = mm.app({
baseDir: 'apps/demo',
customEgg: path.join(__dirname, '../node_modules/egg'),
});
return app.ready();
});
```
也可以通过 customEgg 指定其他框架,比如希望在 aliyun-egg 和 framework-b 同时测试此插件。
```js
describe('aliyun-egg', () => {
let app;
before(() => {
app = mm.app({
baseDir: 'apps/demo',
customEgg: path.join(__dirname, 'node_modules/aliyun-egg'),
});
return app.ready();
});
});
describe('framework-b', () => {
let app;
before(() => {
app = mm.app({
baseDir: 'apps/demo',
customEgg: path.join(__dirname, 'node_modules/framework-b'),
});
return app.ready();
});
});
```
如果当前目录确实是一个 egg 插件,但是又不想当它是一个插件来测试,可以通过 `options.plugin` 选项来关闭:
```js
before(() => {
app = mm.app({
baseDir: 'apps/demo',
customEgg: path.join(__dirname, 'node_modules/egg'),
plugin: false,
});
return app.ready();
});
```
## API
### mm.app(options)
创建一个 mock 的应用。
### mm.cluster(options)
创建一个多进程应用,因为是多进程应用,无法获取 worker 的属性,只能通过 supertest 请求。
```js
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)
});
});
```
默认会启用覆盖率,因为覆盖率比较慢,可以设置 coverage 关闭
```js
mm.cluster({
coverage: false,
});
```
### mm.env(env)
设置环境变量,主要用于启动阶段,运行阶段可以使用 app.mockEnv。
```js
// 模拟生成环境
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 终端日志打印级别
```js
// 不输出到终端
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。
指定完整路径
```js
mm.app({
baseDir: path.join(__dirname, 'fixtures/apps/demo'),
})
```
也支持缩写,找 test/fixtures 目录下的
```js
mm.app({
baseDir: 'apps/demo',
})
```
#### customEgg {String/Boolean}
指定框架路径
```js
mm.app({
baseDir: 'apps/demo',
customEgg: path.join(__dirname, 'fixtures/egg'),
})
```
对于框架的测试用例,可以指定 true,会自动加载当前路径。
#### plugin
指定插件的路径,只用于插件测试。设置为 true 会将当前路径设置到插件列表。
```js
mm.app({
baseDir: 'apps/demo',
plugin: true,
})
```
#### plugins {Object}
传入插件列表,可以自定义多个插件
#### cache {Boolean}
是否需要缓存,默认开启。
是通过 baseDir 缓存的,如果不需要可以关闭,但速度会慢。
#### clean {Boolean}
是否需要清理 log 目录,默认开启。
如果是通过 ava 等并行测试框架进行测试,需要手动在执行测试前进行统一的日志清理,不能通过 mm 来处理,设置 `clean` 为 `false`。
### app.mockLog([logger]) and app.expectLog(str[, logger]), app.notExpectLog(str[, logger])
断言指定的字符串记录在指定的日志中。
建议 `app.mockLog()` 和 `app.expectLog()` 或者 `app.notExpectLog()` 配对使用。
单独使用 `app.expectLog()` 或者 `app.notExpectLog()` 需要依赖日志的写入速度,在服务器磁盘高 IO 的时候,会出现不稳定的结果。
```js
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 服务的辅助工具。
```js
it('should work', () => {
return app.httpRequest()
.get('/')
.expect('hello world')
.expect(200);
});
```
更多信息请查看 [supertest](https://github.com/visionmedia/supertest) 的 API 说明。
#### .unexpectHeader(name)
断言当前请求响应不包含指定 header
```js
it('should work', () => {
return app.httpRequest()
.get('/')
.unexpectHeader('set-cookie')
.expect(200);
});
```
#### .expectHeader(name)
断言当前请求响应包含指定 header
```js
it('should work', () => {
return app.httpRequest()
.get('/')
.expectHeader('set-cookie')
.expect(200);
});
```
### app.mockContext(options)
模拟上下文数据
```js
const ctx = app.mockContext({
user: {
name: 'Jason'
}
});
console.log(ctx.user.name); // Jason
```
### app.mockContextScope(fn, options)
安全的模拟上下文数据,同一用例用多次调用 mockContext 可能会造成 AsyncLocalStorage 污染
```js
await app.mockContextScope(async ctx => {
console.log(ctx.user.name); // Jason
}, {
user: {
name: 'Jason'
}
});
```
### app.mockCookies(data)
```js
app.mockCookies({
foo: 'bar'
});
const ctx = app.mockContext();
console.log(ctx.getCookie('foo'));
```
### app.mockHeaders(data)
模拟请求头
### app.mockSession(data)
```js
app.mockSession({
foo: 'bar'
});
const ctx = app.mockContext();
console.log(ctx.session.foo);
```
### app.mockService(service, methodName, fn)
```js
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)
可以模拟一个错误
```js
app.mockServiceError('user', 'home', new Error('mock error'));
```
### app.mockCsrf()
模拟 csrf,不用传递 token
```js
app.mockCsrf();
return app.httpRequest()
.post('/login')
.expect(302);
```
### app.mockHttpclient(url, method, data)
模拟 httpclient 的请求,例如 `ctx.curl`
```js
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 来减少单测中的重复代码:
```js
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');
});
});
```
我们将会在每个 case 中自定注入 ctx, 可以通过 `app.currentContext` 来获取当前的 ctx。
并且第一次使用 `app.mockContext` 会自动复用当前 case 的上下文。
```js
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;
// 第一次调用会复用上下文
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](https://github.com/eggjs/egg/issues).
## License
[MIT](LICENSE)
## Contributors
[](https://github.com/eggjs/egg-mock/graphs/contributors)
Made with [contributors-img](https://contrib.rocks).
================================================
FILE: app/extend/agent.js
================================================
const mm = require('mm');
const mockHttpclient = require('../../lib/mock_httpclient');
const mockAgent = require('../../lib/mock_agent');
module.exports = {
/**
* mock httpclient
* @function Agent#mockHttpclient
* @param {...any} args - args
* @return {Context} this
*/
mockHttpclient(...args) {
if (!this._mockHttpclient) {
this._mockHttpclient = mockHttpclient(this);
}
return this._mockHttpclient(...args);
},
/**
* get mock httpclient agent
* @function Agent#mockHttpclientAgent
* @return {MockAgent} agent
*/
mockAgent() {
return mockAgent.getAgent(this);
},
async mockAgentRestore() {
await mockAgent.restore();
},
/**
* @see mm#restore
* @function Agent#mockRestore
*/
mockRestore: mm.restore,
/**
* @see mm
* @function Agent#mm
*/
mm,
};
================================================
FILE: app/extend/application.js
================================================
const debug = require('util').debuglog('egg-mock:application');
const mm = require('mm');
const http = require('http');
const fs = require('fs');
const merge = require('merge-descriptors');
const is = require('is-type-of');
const assert = require('assert');
const Transport = require('egg-logger').Transport;
const mockAgent = require('../../lib/mock_agent');
const mockHttpclient = require('../../lib/mock_httpclient');
const supertestRequest = require('../../lib/supertest');
const ORIGIN_TYPES = Symbol('egg-mock:originTypes');
const BACKGROUND_TASKS = Symbol('Application#backgroundTasks');
const REUSED_CTX = Symbol('Context#reusedInSuite');
module.exports = {
/**
* mock Context
* @function App#mockContext
* @param {Object} data - ctx data
* @param {Object} [options] - mock ctx options
* @return {Context} ctx
* @example
* ```js
* const ctx = app.mockContext({
* user: {
* name: 'Jason'
* }
* });
* console.log(ctx.user.name); // Jason
*
* // controller
* module.exports = function*() {
* this.body = this.user.name;
* };
* ```
*/
mockContext(data, options) {
function mockRequest(req) {
for (const key in (data.headers) || {}) {
mm(req.headers, key, data.headers[key]);
mm(req.headers, key.toLowerCase(), data.headers[key]);
}
}
options = Object.assign({ mockCtxStorage: true }, options);
data = data || {};
if (this._customMockContext) {
this._customMockContext(data);
}
// 使用者自定义mock,可以覆盖上面的 mock
for (const key in data) {
mm(this.context, key, data[key]);
}
const req = this.mockRequest(data);
const res = new http.ServerResponse(req);
if (options.reuseCtxStorage !== false) {
if (this.currentContext && !this.currentContext[REUSED_CTX]) {
mockRequest(this.currentContext.request.req);
this.currentContext[REUSED_CTX] = true;
return this.currentContext;
}
}
const ctx = this.createContext(req, res);
if (options.mockCtxStorage) {
mm(this.ctxStorage, 'getStore', () => ctx);
}
return ctx;
},
async mockContextScope(fn, data) {
const ctx = this.mockContext(data, {
mockCtxStorage: false,
reuseCtxStorage: false,
});
return await this.ctxStorage.run(ctx, fn, ctx);
},
/**
* mock cookie session
* @function App#mockSession
* @param {Object} data - session object
* @return {App} this
*/
mockSession(data) {
if (!data) {
return this;
}
if (is.object(data) && !data.save) {
Object.defineProperty(data, 'save', {
value: () => {},
enumerable: false,
});
}
mm(this.context, 'session', data);
return this;
},
/**
* Mock service
* @function App#mockService
* @param {String} service - name
* @param {String} methodName - method
* @param {Object/Function/Error} fn - mock you data
* @return {App} this
*/
mockService(service, methodName, fn) {
if (typeof service === 'string') {
const arr = service.split('.');
service = this.serviceClasses;
for (const key of arr) {
service = service[key];
}
service = service.prototype || service;
}
this._mockFn(service, methodName, fn);
return this;
},
/**
* mock service that return error
* @function App#mockServiceError
* @param {String} service - name
* @param {String} methodName - method
* @param {Error} [err] - error infomation
* @return {App} this
*/
mockServiceError(service, methodName, err) {
if (typeof err === 'string') {
err = new Error(err);
} else if (!err) {
// mockServiceError(service, methodName)
err = new Error('mock ' + methodName + ' error');
}
this.mockService(service, methodName, err);
return this;
},
_mockFn(obj, name, data) {
const origin = obj[name];
assert(is.function(origin), `property ${name} in original object must be function`);
// keep origin properties' type to support mock multitimes
if (!obj[ORIGIN_TYPES]) obj[ORIGIN_TYPES] = {};
let type = obj[ORIGIN_TYPES][name];
if (!type) {
type = obj[ORIGIN_TYPES][name] = is.generatorFunction(origin) || is.asyncFunction(origin) ? 'async' : 'sync';
}
if (is.function(data)) {
const fn = data;
// if original is generator function or async function
// but the mock function is normal function, need to change it return a promise
if (type === 'async' &&
(!is.generatorFunction(fn) && !is.asyncFunction(fn))) {
mm(obj, name, function(...args) {
return new Promise(resolve => {
resolve(fn.apply(this, args));
});
});
return;
}
mm(obj, name, fn);
return;
}
if (type === 'async') {
mm(obj, name, () => {
return new Promise((resolve, reject) => {
if (data instanceof Error) return reject(data);
resolve(data);
});
});
return;
}
mm(obj, name, () => {
if (data instanceof Error) {
throw data;
}
return data;
});
},
/**
* mock request
* @function App#mockRequest
* @param {Request} req - mock request
* @return {Request} req
*/
mockRequest(req) {
req = Object.assign({}, req);
const headers = req.headers || {};
for (const key in req.headers) {
headers[key.toLowerCase()] = req.headers[key];
}
if (!headers['x-forwarded-for']) {
headers['x-forwarded-for'] = '127.0.0.1';
}
req.headers = headers;
merge(req, {
query: {},
querystring: '',
host: '127.0.0.1',
hostname: '127.0.0.1',
protocol: 'http',
secure: 'false',
method: 'GET',
url: '/',
path: '/',
socket: {
remoteAddress: '127.0.0.1',
remotePort: 7001,
},
});
return req;
},
/**
* mock cookies
* @function App#mockCookies
* @param {Object} cookies - cookie
* @return {Context} this
*/
mockCookies(cookies) {
if (!cookies) {
return this;
}
const createContext = this.createContext;
mm(this, 'createContext', function(req, res) {
const ctx = createContext.call(this, req, res);
const getCookie = ctx.cookies.get;
mm(ctx.cookies, 'get', function(key, opts) {
if (cookies[key]) {
return cookies[key];
}
return getCookie.call(this, key, opts);
});
return ctx;
});
return this;
},
/**
* mock header
* @function App#mockHeaders
* @param {Object} headers - header 对象
* @return {Context} this
*/
mockHeaders(headers) {
if (!headers) {
return this;
}
const getHeader = this.request.get;
mm(this.request, 'get', function(field) {
const header = findHeaders(headers, field);
if (header) return header;
return getHeader.call(this, field);
});
return this;
},
/**
* mock csrf
* @function App#mockCsrf
* @return {App} this
* @since 1.11
*/
mockCsrf() {
mm(this.context, 'assertCSRF', () => {});
mm(this.context, 'assertCsrf', () => {});
return this;
},
/**
* mock httpclient
* @function App#mockHttpclient
* @param {...any} args - args
* @return {Context} this
*/
mockHttpclient(...args) {
if (!this._mockHttpclient) {
this._mockHttpclient = mockHttpclient(this);
}
return this._mockHttpclient(...args);
},
mockUrllib(...args) {
this.deprecate('[egg-mock] Please use app.mockHttpclient instead of app.mockUrllib');
return this.mockHttpclient(...args);
},
/**
* get mock httpclient agent
* @function App#mockHttpclientAgent
* @return {MockAgent} agent
*/
mockAgent() {
return mockAgent.getAgent(this);
},
async mockAgentRestore() {
await mockAgent.restore();
},
/**
* @see mm#restore
* @function App#mockRestore
*/
mockRestore: mm.restore,
/**
* @see mm
* @function App#mm
*/
mm,
/**
* override loadAgent
* @function App#loadAgent
*/
loadAgent() {},
/**
* mock serverEnv
* @function App#mockEnv
* @param {String} env - serverEnv
* @return {App} this
*/
mockEnv(env) {
mm(this.config, 'env', env);
mm(this.config, 'serverEnv', env);
return this;
},
/**
* http request helper
* @function App#httpRequest
* @return {SupertestRequest} req - supertest request
* @see https://github.com/visionmedia/supertest
*/
httpRequest() {
return supertestRequest(this);
},
/**
* collection logger message, then can be use on `expectLog()`
* @param {String|Logger} [logger] - logger instance, default is `ctx.logger`
* @function App#mockLog
*/
mockLog(logger) {
logger = logger || this.logger;
if (typeof logger === 'string') {
logger = this.getLogger(logger);
}
// make sure mock once
if (logger._mockLogs) return;
const transport = new Transport(logger.options);
// https://github.com/eggjs/egg-logger/blob/master/lib/logger.js#L64
const log = logger.log;
mm(logger, '_mockLogs', []);
mm(logger, 'log', (level, args, meta) => {
const message = transport.log(level, args, meta);
logger._mockLogs.push(message);
log.apply(logger, [ level, args, meta ]);
});
},
__checkExpectLog(expectOrNot, str, logger) {
logger = logger || this.logger;
if (typeof logger === 'string') {
logger = this.getLogger(logger);
}
const filepath = logger.options.file;
let content;
if (logger._mockLogs) {
content = logger._mockLogs.join('\n');
} else {
content = fs.readFileSync(filepath, 'utf8');
}
let match;
let type;
if (str instanceof RegExp) {
match = str.test(content);
type = 'RegExp';
} else {
match = content.includes(String(str));
type = 'String';
}
if (expectOrNot) {
assert(match, `Can't find ${type}:"${str}" in ${filepath}, log content: ...${content.substring(content.length - 500)}`);
} else {
assert(!match, `Find ${type}:"${str}" in ${filepath}, log content: ...${content.substring(content.length - 500)}`);
}
},
/**
* expect str/regexp in the logger, if your server disk is slow, please call `mockLog()` first.
* @param {String|RegExp} str - test str or regexp
* @param {String|Logger} [logger] - logger instance, default is `ctx.logger`
* @function App#expectLog
*/
expectLog(str, logger) {
this.__checkExpectLog(true, str, logger);
},
/**
* not expect str/regexp in the logger, if your server disk is slow, please call `mockLog()` first.
* @param {String|RegExp} str - test str or regexp
* @param {String|Logger} [logger] - logger instance, default is `ctx.logger`
* @function App#notExpectLog
*/
notExpectLog(str, logger) {
this.__checkExpectLog(false, str, logger);
},
backgroundTasksFinished() {
const tasks = this._backgroundTasks;
debug('waiting %d background tasks', tasks.length);
if (tasks.length === 0) return Promise.resolve();
this._backgroundTasks = [];
return Promise.all(tasks).then(() => {
debug('finished %d background tasks', tasks.length);
if (this._backgroundTasks.length) {
debug('new background tasks created: %s', this._backgroundTasks.length);
return this.backgroundTasksFinished();
}
});
},
get _backgroundTasks() {
if (!this[BACKGROUND_TASKS]) {
this[BACKGROUND_TASKS] = [];
}
return this[BACKGROUND_TASKS];
},
set _backgroundTasks(tasks) {
this[BACKGROUND_TASKS] = tasks;
},
};
function findHeaders(headers, key) {
if (!headers || !key) {
return null;
}
key = key.toLowerCase();
for (const headerKey in headers) {
if (key === headerKey.toLowerCase()) {
return headers[headerKey];
}
}
return null;
}
================================================
FILE: app/middleware/cluster_app_mock.js
================================================
const debug = require('util').debuglog('egg-mock:middleware:cluster_app_mock');
const is = require('is-type-of');
const co = require('co');
module.exports = () => {
return function clusterAppMock(ctx, next) {
// use originalUrl to make sure other middlewares can't change request url
if (ctx.originalUrl !== '/__egg_mock_call_function') return next();
debug('%s %s, body: %j', ctx.method, ctx.url, ctx.request.body);
const { method, property, args, needResult } = ctx.request.body;
if (!method) {
ctx.status = 422;
ctx.body = {
success: false,
error: 'Missing method',
};
return;
}
if (args && !Array.isArray(args)) {
ctx.status = 422;
ctx.body = {
success: false,
error: 'args should be an Array instance',
};
return;
}
if (property) {
if (!ctx.app[property] || typeof ctx.app[property][method] !== 'function') {
ctx.status = 422;
ctx.body = {
success: false,
error: `method "${method}" not exists on app.${property}`,
};
return;
}
} else {
if (typeof ctx.app[method] !== 'function') {
ctx.status = 422;
ctx.body = {
success: false,
error: `method "${method}" not exists on app`,
};
return;
}
}
debug('call %s with %j', method, args);
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg && typeof arg === 'object') {
// convert __egg_mock_type back to function
if (arg.__egg_mock_type === 'function') {
// eslint-disable-next-line
args[i] = eval(`(function() { return ${arg.value} })()`);
} else if (arg.__egg_mock_type === 'error') {
const err = new Error(arg.message);
err.name = arg.name;
err.stack = arg.stack;
for (const key in arg) {
if (key !== 'name' && key !== 'message' && key !== 'stack' && key !== '__egg_mock_type') {
err[key] = arg[key];
}
}
args[i] = err;
}
}
}
const target = property ? ctx.app[property] : ctx.app;
let fn = target[method];
if (is.generatorFunction(fn)) fn = co.wrap(fn);
try {
Promise.resolve(fn.call(target, ...args)).then(result => {
ctx.body = needResult ? { success: true, result } : { success: true };
});
} catch (err) {
ctx.status = 500;
ctx.body = { success: false, error: err.message };
}
};
};
================================================
FILE: app.js
================================================
'use strict';
module.exports = app => {
// make sure clusterAppMock position before securities
const index = app.config.coreMiddleware.indexOf('securities');
if (index >= 0) {
app.config.coreMiddleware.splice(index, 0, 'clusterAppMock');
} else {
app.config.coreMiddleware.push('clusterAppMock');
}
};
================================================
FILE: bootstrap.d.ts
================================================
import * as assert from 'assert';
import { MockApplication, EggMock } from './';
export {
assert
}
export declare const app: MockApplication;
export declare const mock: EggMock;
export declare const mm: EggMock;
================================================
FILE: bootstrap.js
================================================
const assert = require('assert');
const path = require('path');
const mock = require('./index').default;
const appHandler = require('./lib/app_handler');
const { getEggOptions } = require('./lib/utils');
const options = getEggOptions();
// throw error when an egg plugin test is using bootstrap
const pkgInfo = require(path.join(options.baseDir || process.cwd(), 'package.json'));
if (pkgInfo.eggPlugin) throw new Error('DO NOT USE bootstrap to test plugin');
appHandler.setupApp();
module.exports = {
assert,
get app() {
return appHandler.getBootstrapApp();
},
mock,
mm: mock,
};
================================================
FILE: index.d.ts
================================================
import { Application, Context, EggLogger } from 'egg';
import { MockMate } from 'mm';
import { Test } from 'supertest';
import { MockAgent } from 'urllib';
import { Suite } from 'mocha';
export { MockAgent };
export interface EggTest extends Test {
unexpectHeader(name: string, b?: Function): EggTest;
expectHeader(name: string, b?: Function): EggTest;
}
export type Methods = 'get' | 'post' | 'delete' | 'del' | 'put' | 'head' | 'options' | 'patch' | 'trace' | 'connect';
export interface BaseMockApplication<T, C> extends Application {
ready(): Promise<void>;
close(): Promise<void>;
callback(): any;
/**
* mock Context
*/
mockContext(data?: any): C;
/**
* mock Context
*/
mockContextScope<R>(fn: (ctx: C) => Promise<R>, data?: any): Promise<R>;
/**
* mock cookie session
*/
mockSession(data: any): T;
mockCookies(cookies: any): T;
mockHeaders(headers: any): T;
/**
* Mock service
*/
mockService(service: string, methodName: string, fn: any): T;
/**
* mock service that return error
*/
mockServiceError(service: string, methodName: string, err?: Error): T;
mockHttpclient(mockUrl: string | RegExp, mockMethod: string | string[], mockResult: MockHttpClientResult): Application;
mockHttpclient(mockUrl: string | RegExp, mockResult: MockHttpClientResult): Application;
mockAgent(): MockAgent;
mockAgentRestore(): Promise<void>;
mockRestore(): Promise<void>;
/**
* mock csrf
*/
mockCsrf(): T;
/**
* http request helper
*/
httpRequest(): {
[key in Methods]: (url: string) => EggTest;
} & {
[key: string]: (url: string) => EggTest;
};
/**
* mock logger
*/
mockLog(logger?: EggLogger | string): void;
expectLog(expected: string | RegExp, logger?: EggLogger | string): void;
notExpectLog(expected: string | RegExp, logger?: EggLogger | string): void;
/**
* background task
*/
backgroundTasksFinished(): Promise<void>;
}
export interface ResultObject {
data?: string | object | Buffer;
status?: number;
headers?: any;
delay?: number;
persist?: boolean;
repeats?: number;
}
export type ResultFunction = (url?: string, opts?: any) => ResultObject | string | void;
export type MockHttpClientResult = ResultObject | ResultFunction | string;
export interface MockOption {
/**
* The directory of the application
*/
baseDir?: string;
/**
* Custom you plugins
*/
plugins?: any;
/**
* The directory of the egg framework
*/
framework?: string;
/**
* Cache application based on baseDir
*/
cache?: boolean;
/**
* Swtich on process coverage, but it'll be slower
*/
coverage?: boolean;
/**
* Remove $baseDir/logs
*/
clean?: boolean;
}
export type EnvType = 'default' | 'test' | 'prod' | 'local' | 'unittest' | string & {};
export type LogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'NONE';
export interface MockApplication extends BaseMockApplication<Application, Context> { }
export interface EggMock extends MockMate {
/**
* Create a egg mocked application
*/
app: (option?: MockOption) => MockApplication;
/**
* Create a mock cluster server, but you can't use API in application, you should test using supertest
*/
cluster: (option?: MockOption) => MockApplication;
/**
* mock the serverEnv of Egg
*/
env: (env: EnvType) => void;
/**
* mock console level
*/
consoleLevel: (level: LogLevel) => void;
/**
* set EGG_HOME path
*/
home: (homePath: string) => void;
/**
* restore mock
*/
restore: () => any;
/**
* If you use mm.app instead of egg-mock/bootstrap to bootstrap app.
* Should manually call setGetAppCallback,
* then egg-mock will inject ctx for each test case
* @param cb
*/
setGetAppCallback: (cb: (suite: Suite) => Promise<MockApplication> ) => void;
}
declare const mm: EggMock;
export default mm;
================================================
FILE: index.js
================================================
const mm = require('mm');
const cluster = require('./lib/cluster');
const app = require('./lib/app');
const mockAgent = require('./lib/mock_agent');
// egg-bin will set this flag to require files for instrument
if (process.env.EGG_BIN_PREREQUIRE) {
require('./lib/prerequire');
}
/**
* @namespace mm
*/
function mock(...args) {
return mm(...args);
}
module.exports = mock;
module.exports.default = mock;
// inherit & extends mm
Object.assign(mock, mm, {
async restore() {
cluster.restore();
await Promise.all([ mockAgent.restore(), mm.restore() ]);
},
/**
* Create a egg mocked application
* @function mm#app
* @param {Object} [options]
* - {String} baseDir - The directory of the application
* - {Object} plugins - Tustom you plugins
* - {String} framework - The directory of the egg framework
* - {Boolean} [true] cache - Cache application based on baseDir
* - {Boolean} [true] coverage - Swtich on process coverage, but it'll be slower
* - {Boolean} [true] clean - Remove $baseDir/logs
* @return {App} return {@link Application}
* @example
* ```js
* var app = mm.app();
* ```
*/
app,
/**
* Create a egg mocked cluster application
* @function mm#cluster
* @see ClusterApplication
*/
cluster,
/**
* mock the serverEnv of Egg
* @member {Function} mm#env
* @param {String} env - contain default, test, prod, local, unittest
* @see https://github.com/eggjs/egg-core/blob/master/lib/loader/egg_loader.js#L78
*/
env(env) {
mm(process.env, 'EGG_MOCK_SERVER_ENV', env);
mm(process.env, 'EGG_SERVER_ENV', env);
},
/**
* mock console level
* @param {String} level - logger level
*/
consoleLevel(level) {
level = (level || '').toUpperCase();
mm(process.env, 'EGG_LOG', level);
},
home(homePath) {
if (homePath) {
mm(process.env, 'EGG_HOME', homePath);
}
},
setGetAppCallback: require('./lib/app_handler').setGetAppCallback,
});
process.setMaxListeners(100);
process.once('SIGQUIT', () => {
process.exit(0);
});
process.once('SIGTERM', () => {
process.exit(0);
});
process.once('SIGINT', () => {
process.exit(0);
});
================================================
FILE: index.test-d.ts
================================================
import { expectType } from 'tsd';
import { Application, Context } from 'egg';
import { MockApplication, MockAgent, ResultObject } from '.';
import { app, mock, mm } from './bootstrap';
expectType<MockApplication>(app);
expectType<Context>(app.currentContext);
expectType<Context | undefined>(app.ctxStorage.getStore());
expectType<MockApplication>(mock.app());
expectType<MockApplication>(mm.app());
expectType<MockAgent>(mm.app().mockAgent());
expectType<Application>(mm.app().mockHttpclient('url', 'post', { data: 'ok' }));
expectType<Application>(mm.app().mockHttpclient('url', 'post', 'data'));
expectType<Application>(mm.app().mockHttpclient('url', {
data: 'mock response',
repeats: 1,
}));
expectType<Application>(mm.app().mockHttpclient('url', () => {}));
expectType<Application>(mm.app().mockHttpclient('url', 'post', () => {}));
expectType<Application>(mm.app().mockHttpclient('url', 'get', {
data: 'mock response',
repeats: 1,
}));
expectType<void>(app.mockLog());
expectType<void>(app.mockLog('logger'));
expectType<void>(app.mockLog(app.logger));
expectType<void>(app.expectLog('foo string'));
expectType<void>(app.expectLog('foo string', 'coreLogger'));
expectType<void>(app.expectLog('foo string', app.coreLogger));
expectType<void>(app.expectLog(/foo string/));
expectType<void>(app.expectLog(/foo string/, 'coreLogger'));
expectType<void>(app.expectLog(/foo string/, app.coreLogger));
expectType<void>(mm.env('default'));
expectType<void>(mm.env('devserver'));
expectType<Promise<void>>(app.mockAgentRestore());
expectType<Promise<void>>(app.mockRestore());
expectType<Promise<void>>(app.mockContextScope(async () => {}));
expectType<Promise<void>>(app.mockContextScope(async (ctx) => {}));
expectType<Promise<void>>(app.backgroundTasksFinished());
const result: ResultObject = {};
expectType<number>(result.status!);
================================================
FILE: lib/agent_handler.js
================================================
const debug = require('util').debuglog('egg-mock:lib:agent');
const Agent = require('./parallel/agent');
const { getEggOptions } = require('./utils');
let agent;
exports.setupAgent = async () => {
debug('setupAgent call, env.ENABLE_MOCHA_PARALLEL: %s, process.env.AUTO_AGENT: %s, agent: %s',
process.env.ENABLE_MOCHA_PARALLEL, process.env.AUTO_AGENT, !!agent);
if (agent) {
await agent.ready();
return agent;
}
if (process.env.ENABLE_MOCHA_PARALLEL && process.env.AUTO_AGENT) {
agent = Agent(getEggOptions());
await agent.ready();
}
return agent;
};
exports.closeAgent = async () => {
debug('setupAgent call, agent: %s', !!agent);
if (agent) {
await agent.close();
}
};
================================================
FILE: lib/app.js
================================================
const debug = require('util').debuglog('egg-mock:lib:app');
const os = require('os');
const path = require('path');
const EventEmitter = require('events');
const co = require('co');
const is = require('is-type-of');
const { Ready } = require('get-ready');
const { detectPort } = require('detect-port');
const ConsoleLogger = require('egg-logger').EggConsoleLogger;
const { sleep, rimraf } = require('./utils');
const formatOptions = require('./format_options');
const context = require('./context');
const mockCustomLoader = require('./mock_custom_loader');
const mockHttpServer = require('./mock_http_server');
const consoleLogger = new ConsoleLogger({ level: 'INFO' });
const apps = new Map();
const INIT = Symbol('init');
const APP_INIT = Symbol('appInit');
const BIND_EVENT = Symbol('bindEvent');
const INIT_ON_LISTENER = Symbol('initOnListener');
const INIT_ONCE_LISTENER = Symbol('initOnceListener');
const MESSENGER = Symbol('messenger');
const MOCK_APP_METHOD = [
'ready',
'closed',
'close',
'_agent',
'_app',
'on',
'once',
'then',
];
class MockApplication extends EventEmitter {
constructor(options) {
super();
this.options = options;
this.baseDir = options.baseDir;
this.closed = false;
this[APP_INIT] = false;
this[INIT_ON_LISTENER] = new Set();
this[INIT_ONCE_LISTENER] = new Set();
Ready.mixin(this);
// listen once, otherwise will throw exception when emit error without listenr
this.once('error', () => {});
co(this[INIT].bind(this))
.then(() => this.ready(true))
.catch(err => {
if (!this[APP_INIT]) {
this.emit('error', err);
}
consoleLogger.error(err);
this.ready(err);
});
}
* [INIT]() {
if (this.options.beforeInit) {
yield this.options.beforeInit(this);
delete this.options.beforeInit;
}
if (this.options.clean !== false) {
const logDir = path.join(this.options.baseDir, 'logs');
try {
/* istanbul ignore if */
if (os.platform() === 'win32') yield sleep(1000);
yield rimraf(logDir);
} catch (err) {
/* istanbul ignore next */
console.error(`remove log dir ${logDir} failed: ${err.stack}`);
}
}
this.options.clusterPort = yield detectPort();
debug('get clusterPort %s', this.options.clusterPort);
const egg = require(this.options.framework);
const Agent = egg.Agent;
const agent = this._agent = new Agent(Object.assign({}, this.options));
debug('agent instantiate');
yield agent.ready();
debug('agent ready');
const Application = bindMessenger(egg.Application, agent);
const app = this._app = new Application(Object.assign({}, this.options));
// https://github.com/eggjs/egg/blob/8bb7c7e7d59d6aeca4b2ed1eb580368dcb731a4d/lib/egg.js#L125
// egg single mode mount this at start(), so egg-mock should impel it.
app.agent = agent;
agent.app = app;
// egg-mock plugin need to override egg context
Object.assign(app.context, context);
mockCustomLoader(app);
debug('app instantiate');
this[APP_INIT] = true;
debug('this[APP_INIT] = true');
this[BIND_EVENT]();
debug('http server instantiate');
mockHttpServer(app);
yield app.ready();
const msg = {
action: 'egg-ready',
data: this.options,
};
app.messenger._onMessage(msg);
agent.messenger._onMessage(msg);
debug('app ready');
}
[BIND_EVENT]() {
for (const args of this[INIT_ON_LISTENER]) {
debug('on(%s), use cache and pass to app', args);
this._app.on(...args);
this.removeListener(...args);
}
for (const args of this[INIT_ONCE_LISTENER]) {
debug('once(%s), use cache and pass to app', args);
this._app.on(...args);
this.removeListener(...args);
}
}
on(...args) {
if (this[APP_INIT]) {
debug('on(%s), pass to app', args);
this._app.on(...args);
} else {
debug('on(%s), cache it because app has not init', args);
this[INIT_ON_LISTENER].add(args);
super.on(...args);
}
}
once(...args) {
if (this[APP_INIT]) {
debug('once(%s), pass to app', args);
this._app.once(...args);
} else {
debug('once(%s), cache it because app has not init', args);
this[INIT_ONCE_LISTENER].add(args);
super.on(...args);
}
}
/**
* close app
* @return {Promise} promise
*/
close() {
this.closed = true;
const self = this;
const baseDir = this.baseDir;
return co(function* () {
if (self._app) {
yield self._app.close();
} else {
// when app init throws an exception, must wait for app quit gracefully
yield sleep(200);
}
if (self._agent) yield self._agent.close();
apps.delete(baseDir);
debug('delete app cache %s, remain %s', baseDir, [ ...apps.keys() ]);
/* istanbul ignore if */
if (os.platform() === 'win32') yield sleep(1000);
});
}
}
module.exports = function(options) {
options = formatOptions(options);
if (options.cache && apps.has(options.baseDir)) {
const app = apps.get(options.baseDir);
// return cache when it hasn't been killed
if (!app.closed) {
return app;
}
// delete the cache when it's closed
apps.delete(options.baseDir);
}
let app = new MockApplication(options);
app = new Proxy(app, {
get(target, prop) {
// don't delegate properties on MockApplication
if (MOCK_APP_METHOD.includes(prop)) return getProperty(target, prop);
if (!target[APP_INIT]) throw new Error(`can't get ${prop} before ready`);
// it's asynchronous when agent and app are loading,
// so should get the properties after loader ready
debug('proxy handler.get %s', prop);
return target._app[prop];
},
set(target, prop, value) {
if (MOCK_APP_METHOD.includes(prop)) return true;
if (!target[APP_INIT]) throw new Error(`can't set ${prop} before ready`);
debug('proxy handler.set %s', prop);
target._app[prop] = value;
return true;
},
defineProperty(target, prop, descriptor) {
// can't define properties on MockApplication
if (MOCK_APP_METHOD.includes(prop)) return true;
if (!target[APP_INIT]) throw new Error(`can't defineProperty ${prop} before ready`);
debug('proxy handler.defineProperty %s', prop);
Object.defineProperty(target._app, prop, descriptor);
return true;
},
deleteProperty(target, prop) {
// can't delete properties on MockApplication
if (MOCK_APP_METHOD.includes(prop)) return true;
if (!target[APP_INIT]) throw new Error(`can't delete ${prop} before ready`);
debug('proxy handler.deleteProperty %s', prop);
delete target._app[prop];
return true;
},
getOwnPropertyDescriptor(target, prop) {
if (MOCK_APP_METHOD.includes(prop)) return Object.getOwnPropertyDescriptor(target, prop);
if (!target[APP_INIT]) throw new Error(`can't getOwnPropertyDescriptor ${prop} before ready`);
debug('proxy handler.getOwnPropertyDescriptor %s', prop);
return Object.getOwnPropertyDescriptor(target._app, prop);
},
getPrototypeOf(target) {
if (!target[APP_INIT]) throw new Error('can\'t getPrototypeOf before ready');
debug('proxy handler.getPrototypeOf %s');
return Object.getPrototypeOf(target._app);
},
});
apps.set(options.baseDir, app);
return app;
};
function getProperty(target, prop) {
const member = target[prop];
if (is.function(member)) {
return member.bind(target);
}
return member;
}
function bindMessenger(Application, agent) {
const agentMessenger = agent.messenger;
return class MessengerApplication extends Application {
constructor(options) {
super(options);
// enable app to send to a random agent
this.messenger.sendRandom = (action, data) => {
this.messenger.sendToAgent(action, data);
};
// enable agent to send to a random app
agentMessenger.on('egg-ready', () => {
agentMessenger.sendRandom = (action, data) => {
agentMessenger.sendToApp(action, data);
};
});
agentMessenger.send = new Proxy(agentMessenger.send, {
apply: this._sendMessage.bind(this),
});
}
_sendMessage(target, thisArg, [ action, data, to ]) {
const appMessenger = this.messenger;
setImmediate(() => {
if (to === 'app') {
appMessenger._onMessage({ action, data });
} else {
agentMessenger._onMessage({ action, data });
}
});
}
get messenger() {
return this[MESSENGER];
}
set messenger(m) {
m.send = new Proxy(m.send, {
apply: this._sendMessage.bind(this),
});
this[MESSENGER] = m;
}
get [Symbol.for('egg#eggPath')]() { return path.join(__dirname, 'tmp'); }
};
}
================================================
FILE: lib/app_handler.js
================================================
const debug = require('util').debuglog('egg-mock:bootstrap:app_handler');
const mockParallelApp = require('./parallel/app');
const { setupAgent } = require('./agent_handler');
const mock = require('../index').default;
const { getEggOptions } = require('./utils');
let app;
exports.setupApp = () => {
if (app) {
debug('return exists app');
return app;
}
const options = getEggOptions();
debug('env.ENABLE_MOCHA_PARALLEL: %s, process.env.AUTO_AGENT: %s',
process.env.ENABLE_MOCHA_PARALLEL, process.env.AUTO_AGENT);
if (process.env.ENABLE_MOCHA_PARALLEL && process.env.AUTO_AGENT) {
// setup agent first
app = mockParallelApp({
...options,
beforeInit: async _app => {
const agent = await setupAgent();
_app.options.clusterPort = agent.options.clusterPort;
debug('mockParallelApp beforeInit get clusterPort: %s', _app.options.clusterPort);
},
});
debug('mockParallelApp app: %s', !!app);
} else {
app = mock.app(options);
if (typeof beforeAll === 'function') {
// jest
beforeAll(() => app.ready());
afterEach(() => app.backgroundTasksFinished());
afterEach(mock.restore);
}
}
};
let getAppCallback;
exports.setGetAppCallback = cb => {
getAppCallback = cb;
};
exports.getApp = async (suite, test) => {
if (getAppCallback) {
return getAppCallback(suite, test);
}
if (app) {
await app.ready();
}
return app;
};
exports.getBootstrapApp = () => {
return app;
};
================================================
FILE: lib/cluster.js
================================================
const debug = require('util').debuglog('egg-mock:cluster');
const path = require('path');
const os = require('os');
const childProcess = require('child_process');
const Coffee = require('coffee').Coffee;
const { Ready } = require('get-ready');
const co = require('co');
const awaitEvent = require('await-event');
const supertestRequest = require('./supertest');
const { sleep, rimrafSync } = require('./utils');
const formatOptions = require('./format_options');
const clusters = new Map();
const serverBin = path.join(__dirname, 'start-cluster');
const requestCallFunctionFile = path.join(__dirname, 'request_call_function.js');
let masterPort = 17000;
/**
* A cluster version of egg.Application, you can test with supertest
* @example
* ```js
* const mm = require('mm');
* const request = require('supertest');
*
* describe('ClusterApplication', () => {
* let app;
* before(function (done) {
* app = mm.cluster({ baseDir });
* app.ready(done);
* });
*
* after(function () {
* app.close();
* });
*
* it('should 200', function (done) {
* request(app.callback())
* .get('/')
* .expect(200, done);
* });
* });
*/
class ClusterApplication extends Coffee {
/**
* @class
* @param {Object} options
* - {String} baseDir - The directory of the application
* - {Object} plugins - Tustom you plugins
* - {String} framework - The directory of the egg framework
* - {Boolean} [cache=true] - Cache application based on baseDir
* - {Boolean} [coverage=true] - Swtich on process coverage, but it'll be slower
* - {Boolean} [clean=true] - Remove $baseDir/logs
* - {Object} [opt] - opt pass to coffee, such as { execArgv: ['--debug'] }
* ```
*/
constructor(options) {
const opt = options.opt;
delete options.opt;
// incremental port
options.port = options.port || ++masterPort;
// Set 1 worker when test
if (!options.workers) options.workers = 1;
const args = [ JSON.stringify(options) ];
debug('fork %s, args: %s, opt: %j', serverBin, args.join(' '), opt);
super({
method: 'fork',
cmd: serverBin,
args,
opt,
});
Ready.mixin(this);
this.port = options.port;
this.baseDir = options.baseDir;
// print stdout and stderr when DEBUG, otherwise stderr.
this.debug(process.env.DEBUG ? 0 : 2);
// disable coverage
if (options.coverage === false) {
this.coverage(false);
}
process.nextTick(() => {
this.proc.on('message', msg => {
// 'egg-ready' and { action: 'egg-ready' }
const action = msg && msg.action ? msg.action : msg;
switch (action) {
case 'egg-ready':
this.emit('close', 0);
break;
case 'app-worker-died':
case 'agent-worker-died':
this.emit('close', 1);
break;
default:
// ignore it
break;
}
});
});
this.end(() => this.ready(true));
}
/**
* the process that forked
* @member {ChildProcess}
*/
get process() {
return this.proc;
}
/**
* Compatible API for supertest
* @return {ClusterApplication} return the instance
*/
callback() {
return this;
}
/**
* Compatible API for supertest
* @member {String} url
* @private
*/
get url() {
return 'http://127.0.0.1:' + this.port;
}
/**
* Compatible API for supertest
* @return {Object}
* - {Number} port
* @private
*/
address() {
return {
port: this.port,
};
}
/**
* Compatible API for supertest
* @return {ClusterApplication} return the instance
* @private
*/
listen() {
return this;
}
/**
* kill the process
* @return {Promise} promise
*/
close() {
this.closed = true;
const proc = this.proc;
const baseDir = this.baseDir;
return co(function* () {
if (proc.connected) {
proc.kill('SIGTERM');
yield awaitEvent.call(proc, 'exit');
}
clusters.delete(baseDir);
debug('delete cluster cache %s, remain %s', baseDir, [ ...clusters.keys() ]);
/* istanbul ignore if */
if (os.platform() === 'win32') yield sleep(1000);
});
}
// mock app.router.pathFor(name) api
get router() {
const that = this;
return {
pathFor(url) {
return that._callFunctionOnAppWorker('pathFor', [ url ], 'router', true);
},
};
}
/**
* collection logger message, then can be use on `expectLog()`
* it's different from `app.expectLog()`, only support string params.
*
* @param {String} [logger] - logger instance name, default is `logger`
* @function ClusterApplication#expectLog
*/
mockLog(logger) {
logger = logger || 'logger';
this._callFunctionOnAppWorker('mockLog', [ logger ], null, true);
}
/**
* expect str in the logger
* it's different from `app.expectLog()`, only support string params.
*
* @param {String} str - test str
* @param {String} [logger] - logger instance name, default is `logger`
* @function ClusterApplication#expectLog
*/
expectLog(str, logger) {
logger = logger || 'logger';
this._callFunctionOnAppWorker('expectLog', [ str, logger ], null, true);
}
/**
* not expect str in the logger
* it's different from `app.notExpectLog()`, only support string params.
*
* @param {String} str - test str
* @param {String} [logger] - logger instance name, default is `logger`
* @function ClusterApplication#notExpectLog
*/
notExpectLog(str, logger) {
logger = logger || 'logger';
this._callFunctionOnAppWorker('notExpectLog', [ str, logger ], null, true);
}
httpRequest() {
return supertestRequest(this);
}
_callFunctionOnAppWorker(method, args = [], property = undefined, needResult = false) {
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (typeof arg === 'function') {
args[i] = {
__egg_mock_type: 'function',
value: arg.toString(),
};
} else if (arg instanceof Error) {
const errObject = {
__egg_mock_type: 'error',
name: arg.name,
message: arg.message,
stack: arg.stack,
};
for (const key in arg) {
if (key !== 'name' && key !== 'message' && key !== 'stack') {
errObject[key] = arg[key];
}
}
args[i] = errObject;
}
}
const data = {
port: this.port,
method,
args,
property,
needResult,
};
const child = childProcess.spawnSync(process.execPath, [
requestCallFunctionFile,
JSON.stringify(data),
], {
stdio: 'pipe',
});
if (child.stderr && child.stderr.length > 0) {
console.error(child.stderr.toString());
}
let result;
if (child.stdout && child.stdout.length > 0) {
if (needResult) {
result = JSON.parse(child.stdout.toString());
} else {
console.error(child.stdout.toString());
}
}
if (child.status !== 0) {
throw new Error(child.stderr.toString());
}
if (child.error) {
throw child.error;
}
return result;
}
}
module.exports = options => {
options = formatOptions(options);
if (options.cache && clusters.has(options.baseDir)) {
const clusterApp = clusters.get(options.baseDir);
// return cache when it hasn't been killed
if (!clusterApp.closed) {
return clusterApp;
}
// delete the cache when it's closed
clusters.delete(options.baseDir);
}
if (options.clean !== false) {
const logDir = path.join(options.baseDir, 'logs');
try {
rimrafSync(logDir);
} catch (err) {
/* istanbul ignore next */
console.error(`remove log dir ${logDir} failed: ${err.stack}`);
}
}
let clusterApp = new ClusterApplication(options);
clusterApp = new Proxy(clusterApp, {
get(target, prop) {
debug('proxy handler.get %s', prop);
// proxy mockXXX function to app worker
const method = prop;
if (typeof method === 'string' && /^mock\w+$/.test(method) && target[method] === undefined) {
return function mockProxy(...args) {
return target._callFunctionOnAppWorker(method, args, null, true);
};
}
return target[prop];
},
});
clusters.set(options.baseDir, clusterApp);
return clusterApp;
};
// export to let mm.restore() worked
module.exports.restore = () => {
for (const clusterApp of clusters.values()) {
clusterApp.mockRestore();
}
};
// ensure to close App process on test exit.
process.on('exit', () => {
for (const clusterApp of clusters.values()) {
clusterApp.close();
}
});
================================================
FILE: lib/context.js
================================================
'use strict';
// try to use eggUtils.getCalleeFromStack
// ignore it if egg-core module not found
let eggUtils;
try {
eggUtils = require('egg-core').utils;
if (!eggUtils) {
// try to support egg-core@3
eggUtils = require('egg-core/lib/utils');
}
} catch (_) {
// ignore eggUtils
}
module.exports = {
runInBackground(scope) {
/* istanbul ignore next */
const taskName = scope._name || scope.name || (eggUtils && eggUtils.getCalleeFromStack(true));
if (taskName) {
scope._name = taskName;
}
const promise = this._runInBackground(scope);
this.app._backgroundTasks.push(promise);
},
};
================================================
FILE: lib/format_options.js
================================================
const debug = require('util').debuglog('mm');
const path = require('path');
const mm = require('mm');
const utils = require('@eggjs/utils');
/**
* format the options
* @param {Object} options - options
* @return {Object} options
*/
module.exports = function formatOptions(options) {
const defaults = {
baseDir: process.cwd(),
cache: true,
coverage: true,
clean: true,
};
options = Object.assign({}, defaults, options);
// relative path to test/fixtures
// ```js
// formatOptions({ baseDir: 'app' }); // baseDir => $PWD/test/fixtures/app
// ```
if (!path.isAbsolute(options.baseDir)) {
options.baseDir = path.join(process.cwd(), 'test/fixtures', options.baseDir);
}
let framework = options.framework || options.customEgg;
// test for framework
if (framework === true) {
framework = process.cwd();
// disable plugin test when framework test
options.plugin = false;
} else {
// it will throw when framework is not found
framework = utils.getFrameworkPath({ framework, baseDir: options.baseDir });
}
options.customEgg = options.framework = framework;
const plugins = options.plugins = options.plugins || {};
// add self as a plugin
plugins['egg-mock'] = {
enable: true,
path: path.join(__dirname, '..'),
};
// test for plugin
if (options.plugin !== false) {
// add self to plugin list
const pkgPath = path.join(process.cwd(), 'package.json');
const pluginName = getPluginName(pkgPath);
if (options.plugin && !pluginName) {
throw new Error(`should set eggPlugin in ${pkgPath}`);
}
if (pluginName) {
plugins[pluginName] = {
enable: true,
path: process.cwd(),
};
}
}
// mock HOME as baseDir, but ignore if it has been mocked
const env = process.env.EGG_SERVER_ENV;
if (!mm.isMocked(process.env, 'HOME') &&
(env === 'default' || env === 'test' || env === 'prod')) {
mm(process.env, 'HOME', options.baseDir);
}
// disable cache after call mm.env(),
// otherwise it will use cache and won't load again.
if (process.env.EGG_MOCK_SERVER_ENV) {
options.cache = false;
}
debug('format options: %j', options);
return options;
};
function getPluginName(pkgPath) {
try {
const pkg = require(pkgPath);
if (pkg.eggPlugin && pkg.eggPlugin.name) {
return pkg.eggPlugin.name;
}
} catch (_) {
// ignore
}
}
================================================
FILE: lib/http_test.js
================================================
'use strict';
const Test = require('supertest').Test;
class EggTest extends Test {
/**
* Unexpectations:
*
* .unexpectHeader('Content-Type')
* .unexpectHeader('Content-Type', fn)
*
* @return {EggTest}
* @public
*/
unexpectHeader(name, b) {
if (typeof b === 'function') {
this.end(b);
}
// header
if (typeof name === 'string') {
this._asserts.push(this._unexpectHeader.bind(this, name));
}
return this;
}
/**
* Expectations:
*
* .expectHeader('Content-Type')
* .expectHeader('Content-Type', fn)
*
* @return {EggTest}
* @public
*/
expectHeader(name, b) {
if (typeof b === 'function') {
this.end(b);
}
// header
if (typeof name === 'string') {
this._asserts.push(this._expectHeader.bind(this, name));
}
return this;
}
_unexpectHeader(name, res) {
const actual = res.headers[name.toLowerCase()];
if (actual) {
return new Error('unexpected "' + name + '" header field, got "' + actual + '"');
}
}
_expectHeader(name, res) {
const actual = res.headers[name.toLowerCase()];
if (!actual) {
return new Error('expected "' + name + '" header field');
}
}
}
module.exports = EggTest;
================================================
FILE: lib/inject_context.js
================================================
const assert = require('assert');
const debug = require('util').debuglog('egg-mock:inject_context');
const MOCHA_SUITE_APP = Symbol.for('mocha#suite#app');
const appHandler = require('./app_handler');
/**
* Monkey patch the mocha instance with egg context.
*
* @param {Function} mocha -
*/
function injectContext(mocha) {
if (!mocha || mocha._injectContextLoaded) {
return;
}
const { Runner } = mocha;
const runSuite = Runner.prototype.runSuite;
const runTests = Runner.prototype.runTests;
function getTestTitle(suite, test) {
const suiteTitle = suite.root ? 'root suite' : suite.title;
if (!test) {
return `"${suiteTitle}"`;
}
return `"${suiteTitle} - ${test.title}"`;
}
// Inject ctx for before/after.
Runner.prototype.runSuite = async function(suite, fn) {
debug('run suite: %s', suite.title);
let app;
const self = this;
try {
app = await appHandler.getApp(suite);
debug('get app: %s', !!app);
await app.ready();
} catch {
// 可能 app.ready 时报错,不使用失败的 app
app = null;
}
if (!app) {
// app 不存在,直接跳过,在 beforeEach 的 hook 中会报错
// 确保不打乱 mocha 的顺序,防止 mocha 内部状态错误
return runSuite.call(self, suite, fn);
}
let errSuite;
try {
suite.ctx[MOCHA_SUITE_APP] = app;
const mockContextFun = app.mockModuleContextScope || app.mockContextScope;
await mockContextFun.call(app, async function() {
await new Promise(resolve => {
runSuite.call(self, suite, aErrSuite => {
errSuite = aErrSuite;
resolve();
});
});
});
} catch (err) {
// mockContext 失败后动态注册一个 beforeAll hook
// 快速失败,直接阻塞后续用例
suite.beforeAll('egg-mock-mock-ctx-failed', async () => {
throw err;
});
return runSuite.call(self, suite, aErrSuite => {
return fn(aErrSuite);
});
}
return fn(errSuite);
};
// Inject ctx for beforeEach/it/afterEach.
// And ctx with before/after is not same as beforeEach/it/afterEach.
Runner.prototype.runTests = async function(suite, fn) {
const tests = suite.tests.slice();
if (!tests.length) {
return runTests.call(this, suite, fn);
}
const app = suite.ctx[MOCHA_SUITE_APP];
const self = this;
if (!app) {
return runTests.call(self, suite, fn);
}
function done(errSuite) {
suite.tests = tests;
return fn(errSuite);
}
async function next(i) {
const test = tests[i];
if (!test) {
return done();
}
suite.tests = [ test ];
let app;
try {
app = await appHandler.getApp(suite, test);
assert(app, `not found app for test ${getTestTitle(suite, test)}`);
await app.ready();
} catch (err) {
self.fail(test, err);
return next(i + 1);
}
try {
const mockContextFun = app.mockModuleContextScope || app.mockContextScope;
await mockContextFun.call(app, async function() {
return await new Promise(resolve => {
runTests.call(self, suite, () => {
return resolve();
});
});
});
} catch (err) {
self.fail(test, err);
return next(i + 1);
}
return next(i + 1);
}
next(0).catch(err => {
self.fail(suite, err);
done(suite);
});
};
mocha._injectContextLoaded = true;
}
module.exports = injectContext;
================================================
FILE: lib/mock_agent.js
================================================
const { debuglog } = require('util');
let { MockAgent, setGlobalDispatcher, getGlobalDispatcher } = require('urllib');
if (typeof getGlobalDispatcher === 'undefined') {
let urllibNext;
// https://github.com/eggjs/egg/blob/3.x/package.json#L59
try {
// try to use urllib4
urllibNext = require('urllib4');
} catch {
// try to use urllib-next
try {
urllibNext = require('urllib-next');
} catch {
throw new Error('Please install urllib@4');
}
}
MockAgent = urllibNext.MockAgent;
setGlobalDispatcher = urllibNext.setGlobalDispatcher;
getGlobalDispatcher = urllibNext.getGlobalDispatcher;
}
const debug = debuglog('egg-mock:lib:mock_agent');
let _mockAgent;
let _global;
const APP_HTTPCLIENT_AGENT = Symbol('app.httpclient.agent');
const httpClients = [];
module.exports = {
getAgent(app) {
if (!_global) {
_global = getGlobalDispatcher();
}
if (!app?.httpclient?.[APP_HTTPCLIENT_AGENT] && typeof app?.httpclient?.getDispatcher === 'function') {
// save the raw dispatcher
app.httpclient[APP_HTTPCLIENT_AGENT] = app.httpclient.getDispatcher();
httpClients.push(app.httpclient);
debug('add new httpClient, size: %d', httpClients.length);
}
if (!_mockAgent) {
_mockAgent = new MockAgent();
setGlobalDispatcher(_mockAgent);
if (typeof app?.httpclient?.setDispatcher === 'function') {
app.httpclient.setDispatcher(_mockAgent);
}
}
return _mockAgent;
},
async restore() {
if (!_mockAgent) return;
if (_global) {
setGlobalDispatcher(_global);
}
for (const httpClient of httpClients) {
httpClient.setDispatcher(httpClient[APP_HTTPCLIENT_AGENT]);
}
debug('restore httpClient, size: %d', httpClients.length);
const agent = _mockAgent;
_mockAgent = null;
await agent.close();
},
};
================================================
FILE: lib/mock_custom_loader.js
================================================
'use strict';
module.exports = app => {
const customLoader = app.config.customLoader;
if (!customLoader) return;
for (const field of Object.keys(customLoader)) {
const loaderConfig = Object.assign({}, customLoader[field]);
loaderConfig.field = field;
addMethod(loaderConfig);
}
function addMethod(loaderConfig) {
const field = loaderConfig.field;
const appMethodName = 'mock' + field.replace(/^[a-z]/i, s => s.toUpperCase());
if (app[appMethodName]) {
app.coreLogger.warn('Can\'t override app.%s', appMethodName);
return;
}
app[appMethodName] = function(service, methodName, fn) {
if (typeof service === 'string') {
const arr = service.split('.');
service = loaderConfig.inject === 'ctx' ? this[field + 'Classes'] : this[field];
for (const key of arr) {
service = service[key];
}
service = service.prototype || service;
}
this._mockFn(service, methodName, fn);
return this;
};
}
};
================================================
FILE: lib/mock_http_server.js
================================================
'use strict';
const http = require('http');
const SERVER = Symbol('http_server');
module.exports = app => {
let server = app[SERVER] || app.callback();
if (typeof server === 'function') {
server = http.createServer(server);
// cache server, avoid create many times
app[SERVER] = server;
// emit server event just like egg-cluster does
// https://github.com/eggjs/egg-cluster/blob/master/lib/app_worker.js#L52
app.emit('server', server);
}
return server;
};
================================================
FILE: lib/mock_httpclient.js
================================================
const mm = require('mm');
const extend = require('extend2');
const is = require('is-type-of');
const mockAgent = require('./mock_agent');
function matchMethod(mockMethods, method) {
return mockMethods.some(m => m === '*' || m === method);
}
function matchUrl(mockUrl, url) {
if (url === mockUrl) return true;
if (mockUrl instanceof RegExp && url.match(mockUrl)) return true;
return false;
}
function normalizeResult(result) {
if (is.string(result)) {
result = { data: result };
}
if (!result.status) {
result.status = 200;
}
result.data = result.data || '';
if (Buffer.isBuffer(result.data)) {
// do nothing
} else if (typeof result.data === 'object') {
// json
result.data = Buffer.from(JSON.stringify(result.data));
} else if (typeof result.data === 'string') {
// string
result.data = Buffer.from(result.data);
} else {
throw new Error('`mockResult.data` must be buffer, string or json');
}
if (!result.res) {
result.res = {
status: result.status,
};
}
result.responseSize = result.responseSize || 0;
if (result.data) {
result.responseSize = result.data.length;
}
result.headers = result.headers || {};
return result;
}
module.exports = app => {
/**
* mock httpclient
* @function mockHttpclient
* @param {String} mockUrl - url
* @param {String|Array} mockMethod - http method, default is '*'
* @param {Object|Function} mockResult - you data
* - data - buffer / string / json
* - status - http status
* - headers - response header
* - delay - delay the associated reply by a set amount in ms.
* - persist - any matching request will always reply with the defined response indefinitely, default is true
* - repeats - number, any matching request will reply with the defined response a fixed amount of times
* @return {Context} this
*/
const MOCK_CONFIGS = Symbol('MOCK_CONFIGS');
const MOCK_CONFIG_INDEX = Symbol('MOCK_CONFIG_INDEX');
return function mockHttpclient(mockUrl, mockMethod, mockResult) {
if (!mockResult) {
// app.mockHttpclient(mockUrl, mockResult)
mockResult = mockMethod;
mockMethod = '*';
}
if (!Array.isArray(mockMethod)) mockMethod = [ mockMethod ];
mockMethod = mockMethod.map(method => (method || 'GET').toUpperCase());
if (app.config.httpclient.useHttpClientNext) {
// use MockAgent on undici
let mockConfigs = app[MOCK_CONFIGS];
if (!mockConfigs) {
mockConfigs = [];
mm(app, MOCK_CONFIGS, mockConfigs);
}
let mockConfigIndex = -1;
let origin = mockUrl;
let pathname = mockUrl;
if (typeof mockUrl === 'string') {
const urlObject = new URL(mockUrl);
origin = urlObject.origin;
const orginalPathname = urlObject.pathname;
pathname = path => {
if (path === orginalPathname) return true;
// should match /foo?a=1 including query
if (path.includes('?')) return path.startsWith(orginalPathname);
return false;
};
} else if (mockUrl instanceof RegExp) {
let requestOrigin = '';
origin = value => {
requestOrigin = value;
return true;
};
pathname = path => {
for (const config of mockConfigs) {
if (config.mockUrl.test(`${requestOrigin}${path}`)) {
mm(app, MOCK_CONFIG_INDEX, config.mockConfigIndex);
return true;
}
}
return false;
};
mockConfigIndex = mockConfigs.length;
mockConfigs.push({ mockUrl, mockResult, mockConfigIndex });
}
const mockPool = mockAgent.getAgent(app).get(origin);
// persist default is true
const persist = typeof mockResult?.persist === 'boolean' ? mockResult?.persist : true;
mockMethod.forEach(function(method) {
if (method === '*') {
method = () => true;
}
const mockScope = mockPool.intercept({
path: pathname,
method,
}).reply(options => {
// not support mockResult as an async function
const requestUrl = `${options.origin}${options.path}`;
let mockRequestResult;
if (mockConfigIndex >= 0) {
mockResult = mockConfigs[app[MOCK_CONFIG_INDEX]].mockResult;
mockRequestResult = is.function(mockResult) ? mockResult(requestUrl, options) : mockResult;
} else {
mockRequestResult = is.function(mockResult) ? mockResult(requestUrl, options) : mockResult;
}
const result = extend(true, {}, normalizeResult(mockRequestResult));
return {
statusCode: result.status,
data: result.data,
responseOptions: {
headers: result.headers,
},
};
});
if (mockResult?.delay > 0) {
mockScope.delay(mockResult.delay);
}
if (persist) {
mockScope.persist();
} else if (mockResult?.repeats > 0) {
mockScope.times(mockResult.repeats);
}
});
return;
}
const httpclient = app.httpclient;
const rawRequest = httpclient.request;
mm(httpclient, 'requestThunk', _request);
mm(httpclient, 'request', _request);
mm(httpclient, 'curl', _request);
return app;
// support generator rather than callback and promise
async function _request(url, opt) {
opt = opt || {};
opt.method = (opt.method || 'GET').toUpperCase();
opt.headers = opt.headers || {};
if (matchUrl(mockUrl, url) && matchMethod(mockMethod, opt.method)) {
let mockRequestResult = is.function(mockResult) ? mockResult(url, opt) : mockResult;
// support mockResult as an async function
if (is.promise(mockRequestResult)) mockRequestResult = await mockRequestResult;
const result = extend(true, {}, normalizeResult(mockRequestResult));
const response = {
status: result.status,
statusCode: result.status,
headers: result.headers,
size: result.responseSize,
aborted: false,
rt: 1,
keepAliveSocket: result.keepAliveSocket || false,
};
httpclient.emit('request', {
reqId: Date.now(),
url,
args: opt,
ctx: opt.ctx,
});
httpclient.emit('response', {
error: null,
ctx: opt.ctx,
req: {
url,
options: opt,
size: result.requestSize,
},
res: response,
});
if (opt.dataType === 'json') {
try {
result.data = JSON.parse(result.data);
} catch (err) {
err.name = 'JSONResponseFormatError';
throw err;
}
} else if (opt.dataType === 'text') {
result.data = result.data.toString();
}
return result;
}
return rawRequest.call(httpclient, url, opt);
}
};
};
================================================
FILE: lib/parallel/agent.js
================================================
const debug = require('util').debuglog('egg-mock:lib:parallel:agent');
const path = require('path');
const Base = require('sdk-base');
const { detectPort } = require('detect-port');
const context = require('../context');
const formatOptions = require('../format_options');
const { sleep, rimraf } = require('../utils');
const mockCustomLoader = require('../mock_custom_loader');
const {
APP_INIT,
INIT_ONCE_LISTENER,
INIT_ON_LISTENER,
BIND_EVENT,
consoleLogger,
} = require('./util');
class MockAgent extends Base {
constructor(options) {
super({ initMethod: '_init' });
this.options = options;
this.baseDir = options.baseDir;
this.closed = false;
this[APP_INIT] = false;
this[INIT_ON_LISTENER] = new Set();
this[INIT_ONCE_LISTENER] = new Set();
// listen once, otherwise will throw exception when emit error without listenr
this.once('error', err => {
consoleLogger.error(err);
});
}
async _init() {
if (this.options.beforeInit) {
await this.options.beforeInit(this);
delete this.options.beforeInit;
}
if (this.options.clean !== false) {
const logDir = path.join(this.options.baseDir, 'logs');
try {
await rimraf(logDir);
} catch (err) {
/* istanbul ignore next */
console.error(`remove log dir ${logDir} failed: ${err.stack}`);
}
}
this.options.clusterPort = process.env.CLUSTER_PORT = await detectPort();
debug('get clusterPort %s', this.options.clusterPort);
const { Agent } = require(this.options.framework);
const agent = this._instance = new Agent(Object.assign({}, this.options));
// egg-mock plugin need to override egg context
Object.assign(agent.context, context);
mockCustomLoader(agent);
debug('agent instantiate');
this[APP_INIT] = true;
debug('this[APP_INIT] = true');
this[BIND_EVENT]();
await agent.ready();
const msg = {
action: 'egg-ready',
data: this.options,
};
agent.messenger._onMessage(msg);
debug('agent ready');
}
[BIND_EVENT]() {
for (const args of this[INIT_ON_LISTENER]) {
debug('on(%s), use cache and pass to app', args);
this._instance.on(...args);
this.removeListener(...args);
}
for (const args of this[INIT_ONCE_LISTENER]) {
debug('once(%s), use cache and pass to app', args);
this._instance.on(...args);
this.removeListener(...args);
}
}
on(...args) {
if (this[APP_INIT]) {
debug('on(%s), pass to app', args);
this._instance.on(...args);
} else {
debug('on(%s), cache it because app has not init', args);
if (this[INIT_ON_LISTENER]) {
this[INIT_ON_LISTENER].add(args);
}
super.on(...args);
}
}
once(...args) {
if (this[APP_INIT]) {
debug('once(%s), pass to app', args);
this._instance.once(...args);
} else {
debug('once(%s), cache it because app has not init', args);
if (this[INIT_ONCE_LISTENER]) {
this[INIT_ONCE_LISTENER].add(args);
}
super.on(...args);
}
}
/**
* close app
* @return {Promise} promise
*/
async close() {
this.closed = true;
const self = this;
if (self._instance) {
await self._instance.close();
} else {
// when app init throws an exception, must wait for app quit gracefully
await sleep(200);
}
}
}
module.exports = function(options) {
options = formatOptions(options);
return new MockAgent(options);
};
================================================
FILE: lib/parallel/agent_register.js
================================================
console.warn('[deprecated] use `egg-mock/register.js` instead of `egg-mock/lib/parallel/agent_register.js`');
module.exports = require('../../register');
================================================
FILE: lib/parallel/app.js
================================================
const debug = require('util').debuglog('egg-mock:lib:parallel:app');
const Base = require('sdk-base');
const context = require('../context');
const formatOptions = require('../format_options');
const { sleep } = require('../utils');
const mockCustomLoader = require('../mock_custom_loader');
const mockHttpServer = require('../mock_http_server');
const {
proxyApp,
APP_INIT,
INIT_ONCE_LISTENER,
INIT_ON_LISTENER,
BIND_EVENT,
consoleLogger,
} = require('./util');
class MockApplication extends Base {
constructor(options) {
super({ initMethod: '_init' });
this.options = options;
this.baseDir = options.baseDir;
this.closed = false;
this[APP_INIT] = false;
this[INIT_ON_LISTENER] = new Set();
this[INIT_ONCE_LISTENER] = new Set();
// listen once, otherwise will throw exception when emit error without listenr
this.once('error', err => {
consoleLogger.error(err);
});
}
async _init() {
if (this.options.beforeInit) {
await this.options.beforeInit(this);
delete this.options.beforeInit;
}
this.options.clusterPort = this.options.clusterPort || process.env.CLUSTER_PORT;
if (!this.options.clusterPort) {
throw new Error('cannot get env.CLUSTER_PORT, parallel run fail');
}
debug('get clusterPort %s', this.options.clusterPort);
const { Application } = require(this.options.framework);
const app = this._instance = new Application(Object.assign({}, this.options));
// egg-mock plugin need to override egg context
Object.assign(app.context, context);
mockCustomLoader(app);
debug('app instantiate');
this[APP_INIT] = true;
debug('this[APP_INIT] = true');
this[BIND_EVENT]();
debug('http server instantiate');
mockHttpServer(app);
await app.ready();
const msg = {
action: 'egg-ready',
data: this.options,
};
app.messenger._onMessage(msg);
debug('app ready');
}
[BIND_EVENT]() {
for (const args of this[INIT_ON_LISTENER]) {
debug('on(%s), use cache and pass to app', args);
this._instance.on(...args);
this.removeListener(...args);
}
for (const args of this[INIT_ONCE_LISTENER]) {
debug('once(%s), use cache and pass to app', args);
this._instance.on(...args);
this.removeListener(...args);
}
}
on(...args) {
if (this[APP_INIT]) {
debug('on(%s), pass to app', args);
this._instance.on(...args);
} else {
debug('on(%s), cache it because app has not init', args);
if (this[INIT_ON_LISTENER]) {
this[INIT_ON_LISTENER].add(args);
}
super.on(...args);
}
}
once(...args) {
if (this[APP_INIT]) {
debug('once(%s), pass to app', args);
this._instance.once(...args);
} else {
debug('once(%s), cache it because app has not init', args);
if (this[INIT_ONCE_LISTENER]) {
this[INIT_ONCE_LISTENER].add(args);
}
super.on(...args);
}
}
/**
* close app
* @return {Promise} promise
*/
async close() {
this.closed = true;
const self = this;
if (self._instance) {
await self._instance.close();
} else {
// when app init throws an exception, must wait for app quit gracefully
await sleep(200);
}
}
}
module.exports = function(options) {
options = formatOptions(options);
const app = new MockApplication(options);
return proxyApp(app, options);
};
================================================
FILE: lib/parallel/util.js
================================================
const debug = require('util').debuglog('egg-mock:lib:parallel:util');
const ConsoleLogger = require('egg-logger').EggConsoleLogger;
const { getProperty } = require('../utils');
const consoleLogger = new ConsoleLogger({ level: 'INFO' });
const MOCK_APP_METHOD = [
'ready',
'closed',
'close',
'on',
'once',
];
const INIT = Symbol('init');
const APP_INIT = Symbol('appInit');
const BIND_EVENT = Symbol('bindEvent');
const INIT_ON_LISTENER = Symbol('initOnListener');
const INIT_ONCE_LISTENER = Symbol('initOnceListener');
function proxyApp(app) {
const proxyApp = new Proxy(app, {
get(target, prop) {
// don't delegate properties on MockAgent
if (MOCK_APP_METHOD.includes(prop)) return getProperty(target, prop);
if (!target[APP_INIT]) throw new Error(`can't get ${prop} before ready`);
// it's asyncrounus when agent and app are loading,
// so should get the properties after loader ready
debug('proxy handler.get %s', prop);
return target._instance[prop];
},
set(target, prop, value) {
if (MOCK_APP_METHOD.includes(prop)) return true;
if (!target[APP_INIT]) throw new Error(`can't set ${prop} before ready`);
debug('proxy handler.set %s', prop);
target._instance[prop] = value;
return true;
},
defineProperty(target, prop, descriptor) {
// can't define properties on MockAgent
if (MOCK_APP_METHOD.includes(prop)) return true;
if (!target[APP_INIT]) throw new Error(`can't defineProperty ${prop} before ready`);
debug('proxy handler.defineProperty %s', prop);
Object.defineProperty(target._instance, prop, descriptor);
return true;
},
deleteProperty(target, prop) {
// can't delete properties on MockAgent
if (MOCK_APP_METHOD.includes(prop)) return true;
if (!target[APP_INIT]) throw new Error(`can't delete ${prop} before ready`);
debug('proxy handler.deleteProperty %s', prop);
delete target._instance[prop];
return true;
},
getOwnPropertyDescriptor(target, prop) {
if (MOCK_APP_METHOD.includes(prop)) return Object.getOwnPropertyDescriptor(target, prop);
if (!target[APP_INIT]) throw new Error(`can't getOwnPropertyDescriptor ${prop} before ready`);
debug('proxy handler.getOwnPropertyDescriptor %s', prop);
return Object.getOwnPropertyDescriptor(target._instance, prop);
},
getPrototypeOf(target) {
if (!target[APP_INIT]) throw new Error('can\'t getPrototypeOf before ready');
debug('proxy handler.getPrototypeOf %s');
return Object.getPrototypeOf(target._instance);
},
});
return proxyApp;
}
module.exports = {
MOCK_APP_METHOD,
INIT,
APP_INIT,
BIND_EVENT,
INIT_ON_LISTENER,
INIT_ONCE_LISTENER,
proxyApp,
consoleLogger,
};
================================================
FILE: lib/prerequire.js
================================================
const debug = require('util').debuglog('egg-mock:prerequire');
const path = require('path');
const { existsSync } = require('fs');
const globby = require('globby');
const cwd = process.cwd();
const dirs = [];
if (existsSync(path.join(cwd, 'app'))) {
dirs.push('app/**/*.js');
}
// avoid Error: ENOENT: no such file or directory, scandir
if (existsSync(path.join(cwd, 'config'))) {
dirs.push('config/**/*.js');
}
const files = globby.sync(dirs, { cwd });
for (const file of files) {
const filepath = path.join(cwd, file);
try {
debug('%s prerequire %s', process.pid, filepath);
require(filepath);
} catch (err) {
debug('prerequire error %s', err.message);
}
}
================================================
FILE: lib/request_call_function.js
================================================
const httpclient = require('urllib');
const { port, method, args, property, needResult } = JSON.parse(process.argv[2]);
const url = `http://127.0.0.1:${port}/__egg_mock_call_function`;
httpclient.request(url, {
method: 'POST',
data: {
method,
args,
property,
needResult,
},
contentType: 'json',
dataType: 'json',
}).then(({ data }) => {
if (!data.success) {
console.error('POST %s error, method: %s, args: %j', url, method, args);
if (data.error) {
console.error(data.error);
} else if (data.message) {
const err = new Error(data.message);
err.stack = data.stack;
console.error(err);
}
process.exit(2);
}
if (data.result) {
console.log('%j', data.result);
}
process.exit(0);
}).catch(err => {
// ignore ECONNREFUSED error on mockRestore
if (method === 'mockRestore' && err.message.includes('ECONNREFUSED')) {
process.exit(0);
}
console.error('POST %s error, method: %s, args: %j', url, method, args);
console.error(err.stack);
// ignore all error on mockRestore
if (method === 'mockRestore') {
process.exit(0);
} else {
process.exit(1);
}
});
================================================
FILE: lib/start-cluster
================================================
#!/usr/bin/env node
if (process.env.EGG_BIN_PREREQUIRE) require('./prerequire');
const options = JSON.parse(process.argv.slice(2));
require(options.framework).startCluster(options);
================================================
FILE: lib/supertest.js
================================================
'use strict';
const methods = require('methods');
const EggTest = require('./http_test');
const mockHttpServer = require('./mock_http_server');
const pkg = require('../package.json');
// patch from https://github.com/visionmedia/supertest/blob/199506d8dbfe0bb1434fc07c38cdcd1ab4c7c926/index.js#L19
/**
* Test against the given `app`,
* returning a new `Test`.
*
* @param {Application} app
* @return {Test}
* @public
*/
module.exports = app => {
const server = mockHttpServer(app);
const obj = {};
for (const method of methods) {
obj[method] = url => {
// support pathFor(url)
if (url[0] !== '/') {
const realUrl = app.router.pathFor(url);
if (!realUrl) throw new Error(`Can\'t find router:${url}, please check your \'app/router.js\'`);
url = realUrl;
}
const eggTest = new EggTest(server, method, url);
eggTest.set('user-agent', `egg-mock/${pkg.version}`);
return eggTest;
};
}
obj.del = obj.delete;
return obj;
};
================================================
FILE: lib/tmp/.gitkeep
================================================
================================================
FILE: lib/utils.js
================================================
const util = require('util');
const { rm } = require('fs/promises');
const { rmSync } = require('fs');
const is = require('is-type-of');
const setTimeoutPromise = util.promisify(setTimeout);
module.exports = {
async sleep(delay) {
await setTimeoutPromise(delay);
},
async rimraf(filepath) {
await rm(filepath, { force: true, recursive: true });
},
rimrafSync(filepath) {
rmSync(filepath, { force: true, recursive: true });
},
getProperty(target, prop) {
const member = target[prop];
if (is.function(member)) {
return member.bind(target);
}
return member;
},
getEggOptions() {
const options = {};
if (process.env.EGG_BASE_DIR) {
options.baseDir = process.env.EGG_BASE_DIR;
} else {
options.baseDir = process.cwd();
}
if (process.env.EGG_FRAMEWORK) {
options.framework = process.env.EGG_FRAMEWORK;
}
return options;
},
};
================================================
FILE: package.json
================================================
{
"name": "egg-mock",
"version": "5.15.2",
"eggPlugin": {
"name": "egg-mock"
},
"description": "mock server for egg",
"types": "index.d.ts",
"main": "index.js",
"files": [
"app.js",
"index.js",
"index.d.ts",
"bootstrap.js",
"bootstrap.d.ts",
"app",
"lib",
"register.js"
],
"scripts": {
"lint": "eslint lib app index.js test/*.test.js",
"tsd": "tsd",
"test": "npm run lint && npm run tsd && npm run test-local",
"test-local": "egg-bin test -r ./register.js --ts false",
"cov": "egg-bin cov -r ./register.js --ts false",
"ci": "npm run lint && npm run tsd && npm run cov"
},
"dependencies": {
"@eggjs/utils": "^4.0.2",
"@types/supertest": "^2.0.7",
"await-event": "^2.1.0",
"co": "^4.6.0",
"coffee": "^5.2.1",
"detect-port": "^2.0.1",
"egg-logger": "^3.5.0",
"extend2": "^1.0.0",
"get-ready": "^3.1.0",
"globby": "^11.1.0",
"is-type-of": "^2.2.0",
"merge-descriptors": "^1.0.1",
"methods": "^1.1.2",
"mm": "^3.0.2",
"sdk-base": "^4.2.1",
"supertest": "^6.2.4",
"urllib": "3"
},
"peerDependencies": {
"egg": "^3.12.0",
"mocha": "^10.2.0",
"urllib": "^3 || ^4"
},
"devDependencies": {
"@eggjs/tegg": "^3.2.2",
"@eggjs/tegg-config": "^3.2.2",
"@eggjs/tegg-controller-plugin": "^3.2.2",
"@eggjs/tegg-plugin": "^3.2.2",
"@eggjs/tsconfig": "^1.1.0",
"@types/mocha": "^10.0.1",
"@types/node": "20",
"egg": "^3.12.0",
"egg-bin": "^6.0.0",
"egg-errors": "^2.2.1",
"egg-tracer": "^2.0.0",
"eslint": "^8.24.0",
"eslint-config-egg": "^12.0.0",
"mocha": "^10.1.0",
"pedding": "^1.1.0",
"tsd": "^0.31.0",
"typescript": "5"
},
"homepage": "https://github.com/eggjs/egg-mock",
"repository": {
"type": "git",
"url": "git+https://github.com/eggjs/egg-mock.git"
},
"bugs": {
"url": "https://github.com/eggjs/egg/issues"
},
"keywords": [
"egg",
"mock"
],
"engines": {
"node": ">= 14.18.0"
},
"author": "popomore <sakura9515@gmail.com>"
}
================================================
FILE: register.js
================================================
const debug = require('util').debuglog('egg-mock:register');
const mock = require('./index').default;
const agentHandler = require('./lib/agent_handler');
const appHandler = require('./lib/app_handler');
const injectContext = require('./lib/inject_context');
exports.mochaGlobalSetup = async () => {
debug('mochaGlobalSetup, agent.setupAgent() start');
await agentHandler.setupAgent();
debug('mochaGlobalSetup, agent.setupAgent() end');
};
exports.mochaGlobalTeardown = async () => {
debug('mochaGlobalTeardown, agent.closeAgent() start');
await agentHandler.closeAgent();
debug('mochaGlobalTeardown, agent.closeAgent() end');
};
exports.mochaHooks = {
async beforeAll() {
const app = await appHandler.getApp();
debug('mochaHooks.beforeAll call, _app: %s', app);
if (app) {
await app.ready();
}
},
async afterEach() {
const app = await appHandler.getApp();
debug('mochaHooks.afterEach call, _app: %s', app);
if (app) {
await app.backgroundTasksFinished();
}
await mock.restore();
},
async afterAll() {
// skip auto app close on parallel
if (process.env.ENABLE_MOCHA_PARALLEL) return;
const app = await appHandler.getApp();
debug('mochaHooks.afterAll call, _app: %s', app);
if (app) {
await app.close();
}
},
};
/**
* Find active node mocha instances.
*
* @return {Array}
*/
function findNodeJSMocha() {
const children = require.cache || {};
return Object.keys(children)
.filter(function(child) {
const val = children[child].exports;
return typeof val === 'function' && val.name === 'Mocha';
})
.map(function(child) {
return children[child].exports;
});
}
require('mocha');
const modules = findNodeJSMocha();
for (const module of modules) {
injectContext(module);
}
================================================
FILE: test/agent.test.js
================================================
'use strict';
const mm = require('..');
const fs = require('fs');
const path = require('path');
const { rimraf } = require('../lib/utils');
const assert = require('assert');
const fixtures = path.join(__dirname, 'fixtures');
const baseDir = path.join(fixtures, 'agent');
describe('test/agent.test.js', () => {
let app;
afterEach(() => app.close());
afterEach(mm.restore);
it('mock agent ok', async () => {
const filepath = path.join(baseDir, 'run/test.txt');
await rimraf(filepath);
app = mm.app({
baseDir,
});
await app.ready();
assert(fs.readFileSync(filepath, 'utf8') === '123');
});
it('mock agent again ok', done => {
app = mm.app({
baseDir,
});
app.ready(done);
});
it('should cluster-client work', done => {
app = mm.app({ baseDir });
app.ready(() => {
app._agent.client.subscribe('agent sub', data => {
assert(data === 'agent sub');
app.client.subscribe('app sub', data => {
assert(data === 'app sub');
done();
});
});
});
});
it('should agent work ok after ready', function* () {
app = mm.app({ baseDir });
yield app.ready();
assert(app._agent.type === 'agent');
});
it('should FrameworkErrorformater work during agent boot', function* () {
let logMsg;
let catchErr;
mm(process.stderr, 'write', msg => {
logMsg = msg;
});
app = mm.app({ baseDir: path.join(fixtures, 'agent-boot-error') });
try {
yield app.ready();
} catch (err) {
catchErr = err;
}
assert(catchErr.code === 'customPlugin_99');
assert(/framework\.CustomError\: mock error \[ https\:\/\/eggjs\.org\/zh-cn\/faq\/customPlugin_99 \]/.test(logMsg));
});
it('should FrameworkErrorformater work during agent boot ready', function* () {
let logMsg;
let catchErr;
mm(process.stderr, 'write', msg => {
logMsg = msg;
});
app = mm.app({ baseDir: path.join(fixtures, 'agent-boot-ready-error') });
try {
yield app.ready();
} catch (err) {
catchErr = err;
}
assert(catchErr.code === 'customPlugin_99');
assert(/framework\.CustomError\: mock error \[ https\:\/\/eggjs\.org\/zh-cn\/faq\/customPlugin_99 \]/.test(logMsg));
});
});
================================================
FILE: test/app/middleware/cluster_app_mock.test.js
================================================
'use strict';
const assert = require('assert');
const mm = require('../../..');
describe('test/app/middleware/cluster_app_mock.test.js', () => {
let app;
before(() => {
app = mm.app({
baseDir: 'demo',
});
return app.ready();
});
after(() => app.close());
afterEach(mm.restore);
it('should return 422 when method missing', () => {
return app.httpRequest()
.post('/__egg_mock_call_function')
.send({})
.expect(422)
.expect({
success: false,
error: 'Missing method',
});
});
it('should return 422 when args is not Array', () => {
return app.httpRequest()
.post('/__egg_mock_call_function')
.send({ method: 'foo', args: 'hi' })
.expect(422)
.expect({
success: false,
error: 'args should be an Array instance',
});
});
it('should return 422 when method is not exists on app', () => {
return app.httpRequest()
.post('/__egg_mock_call_function')
.send({ method: 'not_exists_method', args: [] })
.expect(422)
.expect({
success: false,
error: 'method "not_exists_method" not exists on app',
});
});
it('should recover error instance', function* () {
let called;
let callError;
mm(app, 'foo', (a, err) => { called = true; callError = err; });
const err = {
__egg_mock_type: 'error',
name: 'FooError',
message: 'foo error fire',
stack: 'error stack',
foo: 'bar',
};
yield app.httpRequest()
.post('/__egg_mock_call_function')
.send({ method: 'foo', args: [ 1, err ] })
.expect(200)
.expect({
success: true,
});
assert(called);
assert(callError.name === 'FooError');
assert(callError.stack === 'error stack');
assert(callError.message === 'foo error fire');
assert(callError.foo === 'bar');
});
});
================================================
FILE: test/app.test.js
================================================
'use strict';
const request = require('supertest');
const path = require('path');
const assert = require('assert');
const mm = require('..');
const fixtures = path.join(__dirname, 'fixtures');
describe('test/app.test.js', () => {
afterEach(mm.restore);
// test mm.app
call('app');
// test mm.cluster
call('cluster');
it('should alias app.agent to app._agent', async () => {
const baseDir = path.join(fixtures, 'app');
const app = mm.app({
baseDir,
customEgg: path.join(__dirname, '../node_modules/egg'),
});
await app.ready();
assert(app.agent === app._agent);
assert(app.agent.app === app._app);
});
it('should not use cache when app is closed', async () => {
const baseDir = path.join(fixtures, 'app');
const app1 = mm.app({
baseDir,
customEgg: path.join(__dirname, '../node_modules/egg'),
});
await app1.ready();
await app1.close();
const app2 = mm.app({
baseDir,
customEgg: path.join(__dirname, '../node_modules/egg'),
});
await app2.ready();
await app2.close();
assert(app1 !== app2);
});
it('should auto find framework when egg.framework exists on package.json', async () => {
const baseDir = path.join(fixtures, 'yadan_app');
const app = mm.app({
baseDir,
});
await app.ready();
assert(app.config.foobar === 'yadan');
await app.close();
});
it('should emit server event on app without superTest', async () => {
const baseDir = path.join(fixtures, 'server');
const app = mm.app({
baseDir,
});
await app.ready();
assert(app.server);
assert(app.emitServer);
await app.close();
});
it('support options.beforeInit', async () => {
const baseDir = path.join(fixtures, 'app');
const app = mm.app({
baseDir,
customEgg: path.join(__dirname, '../node_modules/egg'),
cache: false,
beforeInit(instance) {
return new Promise(resolve => {
setTimeout(() => {
instance.options.test = 'abc';
resolve();
}, 100);
});
},
});
await app.ready();
assert(!app.options.beforeInit);
assert(app.options.test === 'abc');
});
it('should emit error when load Application fail', done => {
const baseDir = path.join(fixtures, 'app-fail');
const app = mm.app({ baseDir, cache: false });
app.once('error', err => {
assert(/load error/.test(err.message));
done();
});
});
it('should FrameworkErrorformater work during app boot', async () => {
let logMsg;
let catchErr;
mm(process.stderr, 'write', msg => {
logMsg = msg;
});
const app = mm.app({ baseDir: path.join(fixtures, 'app-boot-error') });
try {
await app.ready();
} catch (err) {
catchErr = err;
}
assert(catchErr.code === 'customPlugin_99');
assert(/framework\.CustomError\: mock error \[ https\:\/\/eggjs\.org\/zh-cn\/faq\/customPlugin_99 \]/.test(logMsg));
});
it('should FrameworkErrorformater work during app boot ready', async () => {
let logMsg;
let catchErr;
mm(process.stderr, 'write', msg => {
logMsg = msg;
});
const app = mm.app({ baseDir: path.join(fixtures, 'app-boot-ready-error') });
try {
await app.ready();
} catch (err) {
catchErr = err;
}
assert(catchErr.code === 'customPlugin_99');
assert(/framework\.CustomError\: mock error \[ https\:\/\/eggjs\.org\/zh-cn\/faq\/customPlugin_99 \]/.test(logMsg));
});
});
function call(method) {
let app;
describe(`mm.${method}()`, () => {
before(done => {
const baseDir = path.join(fixtures, 'app');
mm(process, 'cwd', () => baseDir);
app = mm[method]({
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/')
.expect('foo')
.expect(200, done);
});
it('should emit server event on app', () => {
return app.httpRequest()
.get('/keepAliveTimeout')
.expect(200)
.expect({
keepAliveTimeout: 5000,
});
});
it('should app.expectLog(), app.notExpectLog() work', async () => {
await app.httpRequest()
.get('/logger')
.expect(200)
.expect({
ok: true,
});
app.expectLog('[app.expectLog() test] ok');
app.expectLog('[app.expectLog() test] ok', 'logger');
app.expectLog('[app.expectLog(coreLogger) test] ok', 'coreLogger');
app.notExpectLog('[app.notExpectLog() test] fail');
app.notExpectLog('[app.notExpectLog() test] fail', 'logger');
app.notExpectLog('[app.notExpectLog(coreLogger) test] fail', 'coreLogger');
if (method === 'app') {
app.expectLog(/\[app\.expectLog\(\) test\] ok/);
app.expectLog(/\[app\.expectLog\(\) test\] ok/, app.logger);
app.expectLog('[app.expectLog(coreLogger) test] ok', app.coreLogger);
app.expectLog(/\[app\.expectLog\(coreLogger\) test\] ok/, 'coreLogger');
app.notExpectLog(/\[app\.notExpectLog\(\) test\] fail/);
app.notExpectLog(/\[app\.notExpectLog\(\) test\] fail/, app.logger);
app.notExpectLog('[app.notExpectLog(coreLogger) test] fail', app.coreLogger);
app.notExpectLog(/\[app\.notExpectLog\(coreLogger\) test\] fail/, 'coreLogger');
}
try {
app.expectLog('[app.expectLog(coreLogger) test] ok');
throw new Error('should not run this');
} catch (err) {
assert(err.message.includes('Can\'t find String:"[app.expectLog(coreLogger) test] ok" in '));
assert(err.message.includes('app-web.log'));
}
try {
app.notExpectLog('[app.expectLog() test] ok');
throw new Error('should not run this');
} catch (err) {
assert(err.message.includes('Find String:"[app.expectLog() test] ok" in '));
assert(err.message.includes('app-web.log'));
}
});
it('should app.mockLog() then app.expectLog() work', async () => {
app.mockLog();
app.mockLog('logger');
app.mockLog('coreLogger');
await app.httpRequest()
.get('/logger')
.expect(200)
.expect({
ok: true,
});
app.expectLog('[app.expectLog() test] ok');
app.expectLog('[app.expectLog() test] ok', 'logger');
app.expectLog('[app.expectLog(coreLogger) test] ok', 'coreLogger');
app.notExpectLog('[app.notExpectLog() test] fail');
app.notExpectLog('[app.notExpectLog() test] fail', 'logger');
app.notExpectLog('[app.notExpectLog(coreLogger) test] fail', 'coreLogger');
if (method === 'app') {
app.expectLog(/\[app\.expectLog\(\) test\] ok/);
app.expectLog(/\[app\.expectLog\(\) test\] ok/, app.logger);
app.expectLog('[app.expectLog(coreLogger) test] ok', app.coreLogger);
app.expectLog(/\[app\.expectLog\(coreLogger\) test\] ok/, 'coreLogger');
app.notExpectLog(/\[app\.notExpectLog\(\) test\] fail/);
app.notExpectLog(/\[app\.notExpectLog\(\) test\] fail/, app.logger);
app.notExpectLog('[app.notExpectLog(coreLogger) test] fail', app.coreLogger);
app.notExpectLog(/\[app\.notExpectLog\(coreLogger\) test\] fail/, 'coreLogger');
}
try {
app.expectLog('[app.expectLog(coreLogger) test] ok');
throw new Error('should not run this');
} catch (err) {
assert(err.message.includes('Can\'t find String:"[app.expectLog(coreLogger) test] ok" in '));
assert(err.message.includes('app-web.log'));
}
try {
app.notExpectLog('[app.expectLog() test] ok');
throw new Error('should not run this');
} catch (err) {
assert(err.message.includes('Find String:"[app.expectLog() test] ok" in '));
assert(err.message.includes('app-web.log'));
}
if (method === 'app') {
assert(app.logger._mockLogs);
assert(app.coreLogger._mockLogs);
await mm.restore();
assert(!app.logger._mockLogs);
assert(!app.coreLogger._mockLogs);
}
});
it('should app.mockLog() don\'t read from file', async () => {
await app.httpRequest()
.get('/logger')
.expect(200)
.expect({
ok: true,
});
app.expectLog('INFO');
app.mockLog();
app.notExpectLog('INFO');
});
it('should request with ua', async () => {
await app.httpRequest()
.get('/ua')
.expect(200)
.expect(/egg-mock\//);
});
});
describe(`mm.${method}({ baseDir, plugin=string })`, () => {
const pluginDir = path.join(fixtures, 'fooPlugin');
before(done => {
mm(process, 'cwd', () => pluginDir);
app = mm[method]({
baseDir: path.join(__dirname, 'fixtures/apps/foo'),
plugin: 'fooPlugin',
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/')
.expect({
fooPlugin: true,
})
.expect(200, done);
});
});
describe(`mm.${method}({ baseDir, plugin=true })`, () => {
const pluginDir = path.join(fixtures, 'fooPlugin');
before(done => {
mm(process, 'cwd', () => pluginDir);
app = mm[method]({
baseDir: path.join(__dirname, 'fixtures/apps/foo'),
plugin: true,
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/')
.expect({
fooPlugin: true,
})
.expect(200, done);
});
});
describe(`mm.${method}({ baseDir, plugins })`, () => {
before(done => {
app = mm[method]({
baseDir: path.join(__dirname, 'fixtures/apps/foo'),
plugins: {
fooPlugin: {
enable: true,
path: path.join(fixtures, 'fooPlugin'),
},
},
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/')
.expect({
fooPlugin: true,
})
.expect(200, done);
});
});
describe(`mm.${method}({ baseDir, customEgg=fullpath})`, () => {
before(done => {
app = mm[method]({
baseDir: 'apps/barapp',
customEgg: path.join(fixtures, 'bar'),
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/')
.expect({
foo: 'bar',
foobar: 'bar',
})
.expect(200, done);
});
});
describe(`mm.${method}({ baseDir, customEgg=true})`, () => {
before(done => {
mm(process, 'cwd', () => {
return path.join(fixtures, 'bar');
});
app = mm[method]({
baseDir: path.join(fixtures, 'apps/barapp'),
customEgg: true,
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/')
.expect({
foo: 'bar',
foobar: 'bar',
})
.expect(200, done);
});
});
describe(`mm.${method}({ baseDir, cache=true })`, () => {
let app1;
let app2;
before(done => {
app1 = mm[method]({
baseDir: 'cache',
coverage: false,
});
app1.ready(done);
});
before(done => {
app2 = mm[method]({
baseDir: 'cache',
coverage: false,
});
app2.ready(done);
});
after(async () => {
await app1.close();
await app2.close();
});
it('should equal', () => {
assert(app1 === app2);
});
});
}
================================================
FILE: test/app_event.test.js
================================================
const path = require('path');
const request = require('supertest');
const pedding = require('pedding');
const assert = require('assert');
const mm = require('..');
const { sleep } = require('../lib/utils');
const fixtures = path.join(__dirname, 'fixtures');
const baseDir = path.join(fixtures, 'app-event');
describe('test/app_event.test.js', () => {
afterEach(mm.restore);
describe('after ready', () => {
let app;
before(() => {
app = mm.app({
baseDir,
cache: false,
});
return app.ready();
});
after(() => app.close());
it('should listen by eventByRequest', done => {
done = pedding(3, done);
app.once('eventByRequest', done);
app.on('eventByRequest', done);
request(app.callback())
.get('/event')
.expect(200)
.expect('done', done);
});
});
describe('before ready', () => {
let app;
beforeEach(() => {
app = mm.app({
baseDir,
cache: false,
});
});
afterEach(() => app.ready());
afterEach(() => app.close());
it('should listen after app ready', done => {
done = pedding(2, done);
app.once('appReady', done);
app.on('appReady', done);
});
it('should listen after app instantiate', done => {
done = pedding(2, done);
app.once('appInstantiated', done);
app.on('appInstantiated', done);
});
});
describe('throw before app init', () => {
let app;
beforeEach(() => {
const baseDir = path.join(fixtures, 'app');
const customEgg = path.join(fixtures, 'error-framework');
app = mm.app({
baseDir,
customEgg,
cache: false,
});
});
afterEach(() => app.close());
it('should listen using app.on', done => {
app.on('error', err => {
assert(err.message === 'start error');
done();
});
});
it('should listen using app.once', done => {
app.once('error', err => {
assert(err.message === 'start error');
done();
});
});
it('should throw error from ready', function* () {
try {
yield app.ready();
} catch (err) {
assert(err.message === 'start error');
}
});
it('should close when app init failed', function* () {
app.once('error', () => {});
yield sleep(1000);
// app._app is undefined
yield app.close();
});
});
});
================================================
FILE: test/app_proxy.test.js
================================================
'use strict';
const path = require('path');
const assert = require('assert');
const mm = require('..');
const fixtures = path.join(__dirname, 'fixtures');
const baseDir = path.join(fixtures, 'app-proxy');
describe('test/app_proxy.test.js', () => {
afterEach(mm.restore);
describe('when before ready', () => {
let app;
const baseDir = path.join(fixtures, 'app-proxy-ready');
before(() => {
app = mm.app({
baseDir,
cache: false,
});
});
after(function* () {
yield app.ready();
yield app.close();
});
it('should not get property', function* () {
assert.throws(() => {
app.config;
}, /can't get config before ready/);
});
it('should not set property', function* () {
assert.throws(() => {
app.curl = function* mockCurl() {
return 'mock';
};
}, /can't set curl before ready/);
});
it('should not define property', function* () {
assert.throws(() => {
Object.defineProperty(app, 'config', {
value: {},
});
}, /can't defineProperty config before ready/);
});
it('should not delete property', function* () {
assert.throws(() => {
delete app.config;
}, /can't delete config before ready/);
});
it('should not getOwnPropertyDescriptor property', function* () {
assert.throws(() => {
Object.getOwnPropertyDescriptor(app, 'config');
}, /can't getOwnPropertyDescriptor config before ready/);
});
it('should not getPrototypeOf property', function* () {
assert.throws(() => {
Object.getPrototypeOf(app);
}, /can't getPrototypeOf before ready/);
});
});
describe('handler.get', () => {
let app;
before(() => {
app = mm.app({
baseDir,
cache: false,
});
return app.ready();
});
after(() => app.close());
it('should get property', () => {
assert(app.getter === 'getter');
assert(app.method() === 'method');
});
it('should ignore when get property on MockApplication', function* () {
assert(app.closed === false);
yield app.close();
assert(app.closed === true);
});
});
describe('handler.set', () => {
let app;
before(() => {
app = mm.app({
baseDir,
cache: false,
});
return app.ready();
});
after(() => app.close());
it('should override property with setter', function* () {
app.curl = function* mockCurl() {
return 'mock';
};
const data = yield app.curl();
assert(data === 'mock');
});
it('should ignore when set property on MockApplication', function* () {
app.closed = true;
assert(app.closed === false);
yield app.close();
});
});
describe('handler.defineProperty', () => {
let app;
before(() => {
app = mm.app({
baseDir,
cache: false,
});
return app.ready();
});
after(() => app.close());
it('should defineProperty', function* () {
assert(app.prop === 1);
Object.defineProperty(app, 'prop', {
get() {
if (!this._prop) {
this._prop = 0;
}
return this._prop++;
},
set(prop) {
if (this._prop) {
this._prop = this._prop + prop;
}
},
});
assert(app.prop === 0);
assert(app.prop === 1);
app.prop = 2;
assert(app.prop === 4);
app.prop = 2;
assert(app.prop === 7);
});
it('should ignore when defineProperty on MockApplication', function* () {
assert(app.closed === false);
Object.defineProperty(app, 'closed', {
value: true,
});
assert(app.closed === false);
assert(!app._app.closed);
});
});
describe('handler.deleteProperty', () => {
let app;
before(() => {
app = mm.app({
baseDir,
cache: false,
});
return app.ready();
});
after(() => app.close());
it('should delete property', () => {
assert(app.shouldBeDelete === true);
delete app.shouldBeDelete;
assert(app.shouldBeDelete === undefined);
});
it('should ignore when delete property on MockApplication', function* () {
assert(!app._app.closed);
assert(app.closed === false);
delete app.closed;
assert(!app._app.closed);
assert(app.closed === false);
});
});
describe('handler.getOwnPropertyDescriptor', () => {
let app;
before(() => {
app = mm.app({
baseDir,
cache: false,
});
return app.ready();
});
after(() => app.close());
it('should getOwnPropertyDescriptor', () => {
const d = Object.getOwnPropertyDescriptor(app, 'a');
assert(typeof d.get === 'function');
assert(typeof d.set === 'function');
});
it('should ignore when getOwnPropertyDescriptor on MockApplication', function* () {
const d = Object.getOwnPropertyDescriptor(app, 'closed');
assert(d.value === false);
});
});
describe('handler.getPrototypeOf', () => {
let app;
before(() => {
app = mm.app({
baseDir,
cache: false,
});
return app.ready();
});
after(() => app.close());
it('should getPrototypeOf', () => {
assert(Object.getPrototypeOf(app) === Object.getPrototypeOf(app._app));
});
});
describe('MOCK_APP_METHOD', () => {
let app;
before(() => {
app = mm.app({
baseDir,
cache: false,
});
return app.ready();
});
after(() => app.close());
it('should be used on MockApplication', () => {
const MOCK_APP_METHOD = [
'ready',
'closed',
'close',
'_agent',
'_app',
'on',
'once',
];
for (const key of MOCK_APP_METHOD) {
assert(app[key] !== app._app[key]);
}
});
});
describe('messenger binding', () => {
let app;
const baseDir = path.join(fixtures, 'messenger-binding');
before(() => {
app = mm.app({
baseDir,
cache: false,
});
return app.ready();
});
after(() => app.close());
it('should send message from app to agent', () => {
assert.deepEqual(app._agent.received, [
'send data when app starting',
'send data when app started',
'send data to a random agent',
]);
});
it('should send message from agent to app', () => {
process.nextTick(() => {
assert.deepEqual(app._app.received, [
'send data when server started',
'send data to a random app',
]);
});
});
it('should receive egg-ready', () => {
assert(app._app.eggReady === true);
assert(app._agent.eggReady === true);
assert(app._agent.eggReadyData.baseDir === baseDir);
assert(app._app.eggReadyData.baseDir === baseDir);
});
it('should broadcast message successfully', () => {
assert(app._app.recievedBroadcastAction === true);
assert(app._agent.recievedBroadcastAction === true);
assert(app._app.recievedAgentRecievedAction === true);
});
it('should send message from app to app', () => {
assert(app._app.recievedAppAction === true);
});
});
});
================================================
FILE: test/bootstrap-plugin.test.js
================================================
'use strict';
const path = require('path');
const coffee = require('coffee');
const mock = require('mm');
describe('test/bootstrap-plugin.test.js', () => {
after(() => mock.restore());
it('should throw', () => {
mock(process.env, 'EGG_BASE_DIR', path.join(__dirname, './fixtures/plugin-bootstrap'));
const testFile = path.join(__dirname, './fixtures/plugin-bootstrap/test.js');
return coffee.fork(testFile)
// .debug()
.expect('stderr', /DO NOT USE bootstrap to test plugin/)
.expect('code', 1)
.end();
});
});
================================================
FILE: test/bootstrap.test.js
================================================
'use strict';
const path = require('path');
const baseDir = process.env.EGG_BASE_DIR = path.join(__dirname, './fixtures/app');
const { app, assert, mm, mock } = require('../bootstrap');
describe('test/bootstrap.test.js', () => {
it('should create app success', () => {
assert(app.baseDir === baseDir);
});
it('should mock and mm success', () => {
assert(app.baseDir === baseDir);
mm(app, 'baseDir', 'foo');
assert(app.baseDir === 'foo');
mock(app, 'baseDir', 'bar');
assert(app.baseDir === 'bar');
});
it('should afterEach(mm.restore) success', () => {
assert(app.baseDir === baseDir);
});
it('should assert success', done => {
try {
assert(app.baseDir !== baseDir);
} catch (err) {
done();
}
});
describe('backgroundTasksFinished()', () => {
it('should wait for background task 1 finished', function* () {
yield app.httpRequest()
.get('/counter')
.expect(200)
.expect({ counter: 0 });
yield app.httpRequest()
.get('/counter/plus')
.expect(200)
.expect({ counter: 0 });
});
it('should wait for background task 2 finished', function* () {
yield app.httpRequest()
.get('/counter')
.expect(200)
.expect({ counter: 1 });
yield app.httpRequest()
.get('/counter/minus')
.expect(200)
.expect({ counter: 1 });
});
it('should wait for background task 3 finished', function* () {
yield app.httpRequest()
.get('/counter')
.expect(200)
.expect({ counter: 0 });
app.mockContext({ superMan: true });
yield app.httpRequest()
.get('/counter/plus')
.expect(200)
.expect({ counter: 0 });
});
it('should wait for background task 4 finished', function* () {
yield app.httpRequest()
.get('/counter')
.expect(200)
.expect({ counter: 10 });
yield app.httpRequest()
.get('/counter/plusplus')
.expect(200)
.expect({ counter: 10 });
});
it('should wait for background task 5 finished', function* () {
yield app.httpRequest()
.get('/counter')
.expect(200)
.expect({ counter: 12 });
app.mockContext({ superMan: true });
yield app.httpRequest()
.get('/counter/plusplus')
.expect(200)
.expect({ counter: 12 });
});
it('should all reset', function* () {
yield app.httpRequest()
.get('/counter')
.expect(200)
.expect({ counter: 32 });
});
it('should always return promise instance', () => {
let p = app.backgroundTasksFinished();
assert(p.then);
p = app.backgroundTasksFinished();
assert(p.then);
p = app.backgroundTasksFinished();
assert(p.then);
});
});
});
================================================
FILE: test/cluster.test.js
================================================
'use strict';
const path = require('path');
const assert = require('assert');
const request = require('supertest');
const mm = require('..');
const fixtures = path.join(__dirname, 'fixtures');
describe('test/cluster.test.js', () => {
afterEach(mm.restore);
describe('normal', () => {
let app;
before(() => {
app = mm.cluster({
baseDir: path.join(fixtures, 'demo'),
cache: false,
coverage: false,
});
// app.debug();
return app.ready();
});
after(() => app.close());
it('should have members', async () => {
assert(app.callback() === app);
assert(app.listen() === app);
await app.ready();
assert(app.process);
});
it('should throw error when mock function not exists', () => {
assert.throws(() => {
app.mockNotExists();
}, /method "mockNotExists" not exists on app/);
});
it('should listen on port', () => {
app.expect('stdout', /egg started on http:\/\/127.0.0.1:17\d{3}/);
});
});
describe('cluster with fullpath baseDir', () => {
let app;
before(done => {
app = mm.cluster({
baseDir: path.join(fixtures, 'demo'),
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/hello')
.expect('hi')
.expect(200, done);
});
});
describe('cluster with shortpath baseDir', () => {
let app;
before(done => {
app = mm.cluster({
baseDir: 'demo',
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/hello')
.expect('hi')
.expect(200, done);
});
});
describe('cluster with customEgg=string', () => {
let app;
before(done => {
app = mm.cluster({
baseDir: 'apps/barapp',
customEgg: path.join(fixtures, 'bar'),
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/')
.expect({
foo: 'bar',
foobar: 'bar',
})
.expect(200, done);
});
});
describe('cluster with customEgg=true', () => {
let app;
before(done => {
mm(process, 'cwd', () => {
return path.join(fixtures, 'bar');
});
app = mm.cluster({
baseDir: path.join(fixtures, 'apps/barapp'),
customEgg: true,
cache: false,
coverage: false,
});
app.ready(done);
});
after(() => app.close());
it('should work', done => {
request(app.callback())
.get('/')
.expect({
foo: 'bar',
foobar: 'bar',
})
.expect(200, done);
});
});
describe('cluster with cache', () => {
let app1;
let app2;
afterEach(() => {
const promises = [];
app1 && promises.push(app1.close());
app2 && promises.push(app2.close());
return Promise.all(promises);
});
it('should return cached cluster app', async () => {
app1 = mm.cluster({
baseDir: 'demo',
coverage: false,
});
await app1.ready();
app2 = mm.cluster({
baseDir: 'demo',
coverage: false,
});
await app2.ready();
assert(app1 === app2);
});
it('should return new app if cached app has been closed', async () => {
app1 = mm.cluster({
baseDir: 'demo',
coverage: false,
});
await app1.ready();
await app1.close();
app2 = mm.cluster({
baseDir: 'demo',
coverage: false,
});
await app2.ready();
assert(app2 !== app1);
});
});
describe('cluster with eggPath', () => {
let app;
after(() => app.close());
it('should get eggPath', async () => {
app = mm.cluster({
baseDir: 'demo',
customEgg: path.join(__dirname, 'fixtures/chair'),
eggPath: '/path/to/eggPath',
cache: false,
coverage: false,
});
await app
.debug()
.expect('stdout', /\/path\/to\/eggPath/)
.end();
});
});
describe('cluster with workers', () => {
let app;
after(() => app.close());
it('should get 2 workers', async () => {
app = mm.cluster({
baseDir: 'demo',
customEgg: path.join(__dirname, 'fixtures/chair'),
workers: 2,
cache: false,
coverage: false,
});
app.debug();
await app.expect('stdout', /app_worker#1:/)
.expect('stdout', /app_worker#2:/)
.end();
});
});
describe('cluster with opts.customEgg', () => {
let app;
after(() => app.close());
it('should pass execArgv', async () => {
app = mm.cluster({
baseDir: 'custom_egg',
customEgg: path.join(__dirname, 'fixtures/bar'),
workers: 1,
cache: false,
coverage: false,
opt: {
execArgv: [ '--inspect' ],
},
});
// app.debug();
await app.expect('stdout', /app_worker#1:/)
.expect('stderr', /Debugger listening/)
.end();
});
});
describe('cluster with egg.framework=yadan', () => {
let app;
after(() => app.close());
it('should pass execArgv', async () => {
app = mm.cluster({
baseDir: 'yadan_app',
workers: 1,
cache: false,
coverage: false,
});
await app.expect('stdout', /app_worker#1:/)
.end();
});
});
describe('prerequire', () => {
let app;
after(() => app.close());
it('should load files', async () => {
mm(process.env, 'EGG_BIN_PREREQUIRE', 'true');
mm(process.env, 'NODE_DEBUG', 'egg-mock:prerequire');
app = mm.cluster({
baseDir: 'yadan_app',
workers: 1,
cache: false,
coverage: false,
});
await app
.expect('stderr', /prerequire .+?\/app\/extend\/application.js/)
.expect('code', 0)
.end();
});
});
describe('custom port', () => {
let app;
after(() => app.close());
it('should use it', async () => {
app = mm.cluster({
baseDir: path.join(fixtures, 'demo'),
cache: false,
coverage: false,
port: 5566,
});
// app.debug();
await app.ready();
app.expect('stdout', /egg started on http:\/\/127.0.0.1:5566/);
});
});
});
================================================
FILE: test/ctx.test.js
================================================
'use strict';
const path = require('path');
const assert = require('assert');
const mm = require('..');
const fixtures = path.join(__dirname, 'fixtures');
describe('test/ctx.test.js', () => {
afterEach(mm.restore);
let app;
before(done => {
app = mm.app({
baseDir: path.join(fixtures, 'demo'),
});
app.ready(done);
});
after(() => app.close());
it('should has logger, app, request', () => {
const ctx = app.mockContext();
assert(ctx.app instanceof Object);
assert(ctx.logger instanceof Object);
assert(ctx.coreLogger instanceof Object);
assert(ctx.request.url === '/');
assert(ctx.request.ip === '127.0.0.1');
});
it('should ctx.ip work', () => {
const ctx = app.mockContext();
ctx.request.headers['x-forwarded-for'] = '';
assert(ctx.request.ip === '127.0.0.1');
});
it('should has services', function* () {
const ctx = app.mockContext();
const data = yield ctx.service.foo.get('foo');
assert(data === 'bar');
});
it('should not override mockData', function* () {
const mockData = { user: 'popomore' };
app.mockContext(mockData);
app.mockContext(mockData);
assert(!mockData.headers);
assert(!mockData.method);
});
describe('mockContextScope', () => {
it('should not conflict with nest call', async () => {
await app.mockContextScope(async ctx => {
const currentStore = app.ctxStorage.getStore();
assert(ctx === currentStore);
await app.mockContextScope(async nestCtx => {
const currentStore = app.ctxStorage.getStore();
assert(nestCtx === currentStore);
});
});
});
it('should not conflict with concurrent call', async () => {
await Promise.all([
await app.mockContextScope(async ctx => {
const currentStore = app.ctxStorage.getStore();
assert(ctx === currentStore);
}),
await app.mockContextScope(async ctx => {
const currentStore = app.ctxStorage.getStore();
assert(ctx === currentStore);
}),
]);
});
});
});
================================================
FILE: test/fixtures/agent/agent.js
================================================
const fs = require('fs');
const path = require('path');
const Client = require('./client');
module.exports = agent => {
const done = agent.readyCallback('agent:agent');
const p = path.join(__dirname, 'run/test.txt');
fs.mkdirSync(path.join(__dirname, 'run'), { recursive: true });
fs.writeFile(p, '123', done);
agent.client = agent.cluster(Client).create();
};
================================================
FILE: test/fixtures/agent/app.js
================================================
'use strict';
const fs = require('fs');
const path = require('path');
const Client = require('./client');
module.exports = function(app) {
const done = app.readyCallback('agent:app');
const p = path.join(__dirname, 'run/test.txt');
setTimeout(() => {
fs.readFile(p, 'utf-8', done);
}, 1000);
app.client = app.cluster(Client).create();
};
================================================
FILE: test/fixtures/agent/client.js
================================================
'use strict';
const Base = require('sdk-base');
class Client extends Base {
constructor() {
super();
this.ready(true);
}
subscribe(topic, listener) {
setTimeout(() => listener(topic), 10);
}
}
module.exports = Client;
================================================
FILE: test/fixtures/agent/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
};
================================================
FILE: test/fixtures/agent/package.json
================================================
{
"name": "demo"
}
================================================
FILE: test/fixtures/agent-boot-error/agent.js
================================================
'use strict';
const { FrameworkBaseError } = require('egg-errors');
class CustomError extends FrameworkBaseError {
get module() {
return 'customPlugin';
}
}
module.exports = class {
configWillLoad() {
throw new CustomError('mock error', 99);
}
};
================================================
FILE: test/fixtures/agent-boot-error/package.json
================================================
{
"name": "agent-boot-error"
}
================================================
FILE: test/fixtures/agent-boot-ready-error/agent.js
================================================
'use strict';
const { FrameworkBaseError } = require('egg-errors');
class CustomError extends FrameworkBaseError {
get module() {
return 'customPlugin';
}
}
module.exports = class {
async didLoad() {
throw new CustomError('mock error', 99);
}
};
================================================
FILE: test/fixtures/agent-boot-ready-error/package.json
================================================
{
"name": "agent-boot-ready-error"
}
================================================
FILE: test/fixtures/app/app/router.js
================================================
const { sleep } = require('../../../../lib/utils');
module.exports = app => {
app.get('/', async ctx => {
ctx.body = 'foo';
});
app.get('/keepAliveTimeout', async ctx => {
ctx.body = {
keepAliveTimeout: ctx.app.serverKeepAliveTimeout,
};
});
app.get('/ua', async ctx => {
ctx.body = ctx.get('user-agent');
});
app.get('/logger', async ctx => {
ctx.logger.info('[app.expectLog() test] ok');
ctx.coreLogger.info('[app.expectLog(coreLogger) test] ok');
ctx.body = { ok: true };
});
let counter = 0;
app.get('/counter', async ctx => {
ctx.body = { counter };
});
app.get('/counter/plus', async ctx => {
ctx.runInBackground(async ctx => {
// mock io delay
await sleep(10);
if (ctx.superMan) {
counter += 10;
return;
}
counter++;
});
ctx.body = { counter };
});
app.get('/counter/minus', async ctx => {
ctx.runInBackground(async () => {
await sleep(10);
counter--;
});
ctx.body = { counter };
});
app.get('/counter/plusplus', async ctx => {
ctx.runInBackground(async ctx => {
// mock io delay
await sleep(10);
if (ctx.superMan) {
counter += 10;
} else {
counter++;
}
ctx.runInBackground(async ctx => {
// mock io delay
await sleep(10);
if (ctx.superMan) {
counter += 10;
} else {
counter++;
}
});
});
ctx.body = { counter };
});
};
================================================
FILE: test/fixtures/app/app.js
================================================
'use strict';
module.exports = app => {
app.on('server', server => {
app.serverKeepAliveTimeout = server.keepAliveTimeout || 5000;
});
};
================================================
FILE: test/fixtures/app/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
};
================================================
FILE: test/fixtures/app/package.json
================================================
{
"name": "app"
}
================================================
FILE: test/fixtures/app-boot-error/app.js
================================================
'use strict';
const { FrameworkBaseError } = require('egg-errors');
class CustomError extends FrameworkBaseError {
get module() {
return 'customPlugin';
}
}
module.exports = class {
configWillLoad() {
throw new CustomError('mock error', 99);
}
};
================================================
FILE: test/fixtures/app-boot-error/package.json
================================================
{
"name": "app-boot-error"
}
================================================
FILE: test/fixtures/app-boot-ready-error/app.js
================================================
'use strict';
const { FrameworkBaseError } = require('egg-errors');
class CustomError extends FrameworkBaseError {
get module() {
return 'customPlugin';
}
}
module.exports = class {
async didLoad() {
throw new CustomError('mock error', 99);
}
};
================================================
FILE: test/fixtures/app-boot-ready-error/package.json
================================================
{
"name": "app-boot-ready-error"
}
================================================
FILE: test/fixtures/app-event/agent.js
================================================
'use strict';
module.exports = app => {
app.ready(() => {
app.emit('agentInstantiated');
});
};
================================================
FILE: test/fixtures/app-event/app/router.js
================================================
'use strict';
module.exports = function(app) {
app.get('/event', function* () {
this.app.emit('eventByRequest');
this.body = 'done';
});
};
================================================
FILE: test/fixtures/app-event/app.js
================================================
'use strict';
const { sleep } = require('../../../lib/utils');
module.exports = app => {
app.ready(() => {
// after ready
app.emit('appReady');
});
process.nextTick(() => {
// before ready, after app instantiate
app.emit('appInstantiated');
});
app.beforeStart(function* () {
yield sleep(1000);
});
};
================================================
FILE: test/fixtures/app-event/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
};
================================================
FILE: test/fixtures/app-event/package.json
================================================
{
"name": "app-event"
}
================================================
FILE: test/fixtures/app-fail/app/router.js
================================================
'use strict';
throw new Error('load error');
================================================
FILE: test/fixtures/app-fail/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
};
================================================
FILE: test/fixtures/app-fail/package.json
================================================
{
"name": "egg-mock"
}
================================================
FILE: test/fixtures/app-proxy/app/extend/application.js
================================================
'use strict';
module.exports = {
get getter() {
return 'getter';
},
method() {
return 'method';
},
prop: 1,
shouldBeDelete: true,
get a() {
return 'a';
},
set a(x) {
this._a = x;
},
};
================================================
FILE: test/fixtures/app-proxy/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
};
================================================
FILE: test/fixtures/app-proxy/package.json
================================================
{
"name": "app-proxy"
}
================================================
FILE: test/fixtures/app-proxy-ready/agent.js
================================================
'use strict';
const { sleep } = require('../../../lib/utils');
module.exports = app => {
// set timeout let testcase ran before ready
app.beforeStart(function* () {
yield sleep(1000);
});
};
================================================
FILE: test/fixtures/app-proxy-ready/app.js
================================================
'use strict';
module.exports = app => {
app.emit('eventOnReady');
app.emit('eventOnReady');
app.emit('eventOnceReady');
app.emit('eventOnceReady');
};
================================================
FILE: test/fixtures/app-proxy-ready/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
};
================================================
FILE: test/fixtures/app-proxy-ready/package.json
================================================
{
"name": "app-proxy-ready"
}
================================================
FILE: test/fixtures/app-ready-failed/app.js
================================================
module.exports = class AppHook {
async didLoad() {
throw new Error('mock app ready failed');
}
};
================================================
FILE: test/fixtures/app-ready-failed/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
};
================================================
FILE: test/fixtures/app-ready-failed/package.json
================================================
{
"name": "app"
}
================================================
FILE: test/fixtures/app-ready-failed/test/index.test.js
================================================
const assert = require('assert');
const { app } = require('../../../../bootstrap');
describe('test for app ready failed', () => {
it('should not print', () => {
// ...
assert(app);
});
});
================================================
FILE: test/fixtures/apps/app-not-clean/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
};
================================================
FILE: test/fixtures/apps/app-not-clean/logs/keep
================================================
================================================
FILE: test/fixtures/apps/app-not-clean/package.json
================================================
{
"name": "app-not-clean"
}
================================================
FILE: test/fixtures/apps/app-throw/app/router.js
================================================
'use strict';
module.exports = app => {
app.get('/throw', function* () {
this.body = 'foo';
setTimeout(() => {
/* eslint-disable-next-line */
a.b = c;
}, 1);
});
app.get('/throw-unhandledRejection', function* () {
this.body = 'foo';
new Promise((resolve, reject) => {
reject(new Error('foo reject error'));
});
});
app.get('/throw-unhandledRejection-string', function* () {
this.body = 'foo';
new Promise((resolve, reject) => {
reject(new Error('foo reject string error'));
});
});
app.get('/throw-unhandledRejection-obj', function* () {
this.body = 'foo';
new Promise((resolve, reject) => {
const err = {
name: 'TypeError',
message: 'foo reject obj error',
stack: new Error().stack,
toString() {
return this.name + ': ' + this.message;
},
};
reject(err);
});
});
};
================================================
FILE: test/fixtures/apps/app-throw/config/config.default.js
================================================
'use strict';
exports.keys = 'test key';
================================================
FILE: test/fixtures/apps/app-throw/config/config.unittest.js
================================================
'use strict';
exports.logger = {
consoleLevel: 'NONE',
};
================================================
FILE: test/fixtures/apps/app-throw/package.json
================================================
{
"name": "app-throw"
}
================================================
FILE: test/fixtures/apps/barapp/app/controller/home.js
================================================
'use strict';
module.exports = function* () {
this.body = {
foo: this.app.config.foo,
foobar: this.app.config.foobar,
};
};
================================================
FILE: test/fixtures/apps/barapp/app/router.js
================================================
'use strict';
module.exports = function(app) {
app.get('/', app.controller.home);
};
================================================
FILE: test/fixtures/apps/barapp/config/config.default.js
================================================
'use strict';
exports.foo = 'bar';
exports.keys = '123';
================================================
FILE: test/fixtures/apps/barapp/package.json
================================================
{
"name": "barapp"
}
================================================
FILE: test/fixtures/apps/env-app/config/config.default.js
================================================
'use strict';
exports.fakeplugin = {
foo: 'bar-default',
};
exports.logger = {
consoleLevel: 'NONE',
};
exports.development = {
fastReady: false,
};
exports.keys = '123';
================================================
FILE: test/fixtures/apps/env-app/config/config.local.js
================================================
'use strict';
exports.development = {
fastReady: false,
};
================================================
FILE: test/fixtures/apps/env-app/config/config.prod.js
================================================
'use strict';
exports.fakeplugin = {
foo: 'bar-prod',
};
================================================
FILE: test/fixtures/apps/env-app/config/config.test.js
================================================
'use strict';
exports.fakeplugin = {
foo: 'bar-test',
};
================================================
FILE: test/fixtures/apps/env-app/config/config.unittest.js
================================================
'use strict';
exports.fakeplugin = {
foo: 'bar-unittest',
};
================================================
FILE: test/fixtures/apps/env-app/package.json
================================================
{
"name": "env-app"
}
================================================
FILE: test/fixtures/apps/foo/app/router.js
================================================
'use strict';
module.exports = function(app) {
app.get('/', function* () {
this.body = {
fooPlugin: app.fooPlugin,
};
});
};
================================================
FILE: test/fixtures/apps/foo/config/config.default.js
================================================
'use strict';
exports.keys = '123';
================================================
FILE: test/fixtures/apps/foo/package.json
================================================
{
"name": "foo"
}
================================================
FILE: test/fixtures/apps/mock_cookies/app/router.js
================================================
'use strict';
module.exports = function(app) {
app.get('/', function* () {
this.body = {
cookieValue: this.cookies.get('foo', { signed: false }) || undefined,
cookiesValue: this.cookies.get('foo', { signed: false }) || undefined,
};
});
};
================================================
FILE: test/fixtures/apps/mock_cookies/config/config.default.js
================================================
'use strict';
exports.keys = '123';
================================================
FILE: test/fixtures/apps/mock_cookies/package.json
================================================
{
"name": "mockCookies"
}
================================================
FILE: test/fixtures/apps/mockhome/config/config.default.js
================================================
'use strict';
exports.keys = '123';
================================================
FILE: test/fixtures/apps/mockhome/package.json
================================================
{
"name": "mockhome"
}
================================================
FILE: test/fixtures/apps/no-framework/config/plugin.js
================================================
'use strict';
const path = require('path');
module.exports = {
a: {
enable: true,
path: path.join(__dirname, '../plugin/a'),
},
};
================================================
FILE: test/fixtures/apps/no-framework/package.json
================================================
{
"name": "no-framework"
}
================================================
FILE: test/fixtures/apps/no-framework/plugin/a/app/extend/application.js
================================================
'use strict';
module.exports = {
mockEnv() {
this.config.env = 'mocked by plugin';
},
};
================================================
FILE: test/fixtures/apps/no-framework/plugin/a/package.json
================================================
{
"eggPlugin": {
"name": "a",
"dependencies": [
"egg-mock"
]
}
}
================================================
FILE: test/fixtures/apps/parallel-test/package.json
================================================
{
"name": "foo"
}
================================================
FILE: test/fixtures/apps/parallel-test/test/a.test.js
================================================
const mm = require('../../../../../');
const assert = require('assert');
describe('test/parallel_a.test.js', () => {
it('should work', () => {
mm(global, 'test', '233');
assert(global.test === '233');
});
});
================================================
FILE: test/fixtures/apps/parallel-test/test/b.test.js
================================================
const mm = require('../../../../../');
const assert = require('assert');
describe('test/parallel_b.test.js', () => {
it('should work', () => {
mm(global, 'test', '244');
assert(global.test === '244');
});
});
================================================
FILE: test/fixtures/apps/parallel-test/test/c.test.js
================================================
const assert = require('assert');
describe('test/parallel_a.test.js', () => {
it('should work', () => {
assert(!global.test);
});
});
================================================
FILE: test/fixtures/bar/config/config.default.js
================================================
'use strict';
exports.foobar = 'bar';
exports.keys = '123';
================================================
FILE: test/fixtures/bar/index.js
================================================
'use strict';
const egg = require('egg');
const EGG_PATH = Symbol.for('egg#eggPath');
class BarApplication extends egg.Application {
get [EGG_PATH]() {
return __dirname;
}
}
Object.assign(exports, egg);
exports.Application = BarApplication;
================================================
FILE: test/fixtures/bar/package.json
================================================
{
"name": "bar",
"version": "1.0.0"
}
================================================
FILE: test/fixtures/cache/config.default.js
================================================
'use strict';
exports.keys = '123';
================================================
FILE: test/fixtures/cache/package.json
================================================
{
"name": "cache"
}
================================================
FILE: test/fixtures/chair/index.js
================================================
'use strict';
const egg = require('egg');
function startCluster(options) {
// print for the testcase that will assert stdout
console.log(options.eggPath);
delete options.eggPath;
egg.startCluster(options);
}
Object.assign(exports, egg, { startCluster });
================================================
FILE: test/fixtures/chair/package.json
================================================
{
"name": "chair"
}
================================================
FILE: test/fixtures/create-context-failed/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
};
================================================
FILE: test/fixtures/create-context-failed/package.json
================================================
{
"name": "app"
}
================================================
FILE: test/fixtures/create-context-failed/test/index.test.js
================================================
const { setGetAppCallback } = require('../../../..');
setGetAppCallback(() => {
return {
ready: async () => {
// ...
},
mockContextScope: async () => {
throw new Error('mock create context failed');
},
close: async () => {
// ...
},
backgroundTasksFinished: async () => {
// ...
},
};
});
describe('test case create context error', () => {
it('should not print', () => {
});
});
================================================
FILE: test/fixtures/custom-loader/app/adapter/docker.js
================================================
'use strict';
class DockerAdapter {
constructor(app) {
this.app = app;
}
async inspectDocker() {
return 'docker';
}
}
module.exports = DockerAdapter;
================================================
FILE: test/fixtures/custom-loader/app/controller/user.js
================================================
'use strict';
class UserController {
constructor(ctx) {
this.ctx = ctx;
this.app = ctx.app;
}
async get() {
this.ctx.body = {
adapter: await this.app.adapter.docker.inspectDocker(),
repository: await this.ctx.repository.user.get(),
};
}
}
module.exports = UserController;
================================================
FILE: test/fixtures/custom-loader/app/repository/user.js
================================================
'use strict';
class UserRepository {
constructor(ctx) {
this.ctx = ctx;
}
async get() {
return this.ctx.params.name;
}
}
module.exports = UserRepository;
================================================
FILE: test/fixtures/custom-loader/app/router.js
================================================
'use strict';
module.exports = app => {
app.router.get('/users/:name', app.controller.user.get);
};
================================================
FILE: test/fixtures/custom-loader/config/config.default.js
================================================
'use strict';
module.exports = {
keys: '123',
customLoader: {
adapter: {
directory: 'app/adapter',
inject: 'app',
},
repository: {
directory: 'app/repository',
inject: 'ctx',
gitextract_75m1jveo/
├── .eslintrc
├── .github/
│ └── workflows/
│ ├── nodejs.yml
│ ├── pkg.pr.new.yml
│ └── release.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.zh_CN.md
├── app/
│ ├── extend/
│ │ ├── agent.js
│ │ └── application.js
│ └── middleware/
│ └── cluster_app_mock.js
├── app.js
├── bootstrap.d.ts
├── bootstrap.js
├── index.d.ts
├── index.js
├── index.test-d.ts
├── lib/
│ ├── agent_handler.js
│ ├── app.js
│ ├── app_handler.js
│ ├── cluster.js
│ ├── context.js
│ ├── format_options.js
│ ├── http_test.js
│ ├── inject_context.js
│ ├── mock_agent.js
│ ├── mock_custom_loader.js
│ ├── mock_http_server.js
│ ├── mock_httpclient.js
│ ├── parallel/
│ │ ├── agent.js
│ │ ├── agent_register.js
│ │ ├── app.js
│ │ └── util.js
│ ├── prerequire.js
│ ├── request_call_function.js
│ ├── start-cluster
│ ├── supertest.js
│ ├── tmp/
│ │ └── .gitkeep
│ └── utils.js
├── package.json
├── register.js
└── test/
├── agent.test.js
├── app/
│ └── middleware/
│ └── cluster_app_mock.test.js
├── app.test.js
├── app_event.test.js
├── app_proxy.test.js
├── bootstrap-plugin.test.js
├── bootstrap.test.js
├── cluster.test.js
├── ctx.test.js
├── fixtures/
│ ├── agent/
│ │ ├── agent.js
│ │ ├── app.js
│ │ ├── client.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── agent-boot-error/
│ │ ├── agent.js
│ │ └── package.json
│ ├── agent-boot-ready-error/
│ │ ├── agent.js
│ │ └── package.json
│ ├── app/
│ │ ├── app/
│ │ │ └── router.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-boot-error/
│ │ ├── app.js
│ │ └── package.json
│ ├── app-boot-ready-error/
│ │ ├── app.js
│ │ └── package.json
│ ├── app-event/
│ │ ├── agent.js
│ │ ├── app/
│ │ │ └── router.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-fail/
│ │ ├── app/
│ │ │ └── router.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-proxy/
│ │ ├── app/
│ │ │ └── extend/
│ │ │ └── application.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-proxy-ready/
│ │ ├── agent.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── app-ready-failed/
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── apps/
│ │ ├── app-not-clean/
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ ├── logs/
│ │ │ │ └── keep
│ │ │ └── package.json
│ │ ├── app-throw/
│ │ │ ├── app/
│ │ │ │ └── router.js
│ │ │ ├── config/
│ │ │ │ ├── config.default.js
│ │ │ │ └── config.unittest.js
│ │ │ └── package.json
│ │ ├── barapp/
│ │ │ ├── app/
│ │ │ │ ├── controller/
│ │ │ │ │ └── home.js
│ │ │ │ └── router.js
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ └── package.json
│ │ ├── env-app/
│ │ │ ├── config/
│ │ │ │ ├── config.default.js
│ │ │ │ ├── config.local.js
│ │ │ │ ├── config.prod.js
│ │ │ │ ├── config.test.js
│ │ │ │ └── config.unittest.js
│ │ │ └── package.json
│ │ ├── foo/
│ │ │ ├── app/
│ │ │ │ └── router.js
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ └── package.json
│ │ ├── mock_cookies/
│ │ │ ├── app/
│ │ │ │ └── router.js
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ └── package.json
│ │ ├── mockhome/
│ │ │ ├── config/
│ │ │ │ └── config.default.js
│ │ │ └── package.json
│ │ ├── no-framework/
│ │ │ ├── config/
│ │ │ │ └── plugin.js
│ │ │ ├── package.json
│ │ │ └── plugin/
│ │ │ └── a/
│ │ │ ├── app/
│ │ │ │ └── extend/
│ │ │ │ └── application.js
│ │ │ └── package.json
│ │ └── parallel-test/
│ │ ├── package.json
│ │ └── test/
│ │ ├── a.test.js
│ │ ├── b.test.js
│ │ └── c.test.js
│ ├── bar/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── index.js
│ │ └── package.json
│ ├── cache/
│ │ ├── config.default.js
│ │ └── package.json
│ ├── chair/
│ │ ├── index.js
│ │ └── package.json
│ ├── create-context-failed/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── custom-loader/
│ │ ├── app/
│ │ │ ├── adapter/
│ │ │ │ └── docker.js
│ │ │ ├── controller/
│ │ │ │ └── user.js
│ │ │ ├── repository/
│ │ │ │ └── user.js
│ │ │ └── router.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── custom_egg/
│ │ └── package.json
│ ├── demo/
│ │ ├── app/
│ │ │ ├── context.js
│ │ │ ├── controller/
│ │ │ │ ├── file.js
│ │ │ │ ├── home.js
│ │ │ │ ├── session.js
│ │ │ │ └── user.js
│ │ │ ├── extend/
│ │ │ │ └── application.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ ├── old.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── demo-async/
│ │ ├── app/
│ │ │ ├── controller/
│ │ │ │ └── home.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── demo_next/
│ │ ├── app/
│ │ │ ├── context.js
│ │ │ ├── controller/
│ │ │ │ ├── file.js
│ │ │ │ ├── home.js
│ │ │ │ ├── session.js
│ │ │ │ └── user.js
│ │ │ ├── extend/
│ │ │ │ └── application.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ ├── old.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── demo_next_h2/
│ │ ├── app/
│ │ │ ├── context.js
│ │ │ ├── controller/
│ │ │ │ ├── file.js
│ │ │ │ ├── home.js
│ │ │ │ ├── session.js
│ │ │ │ └── user.js
│ │ │ ├── extend/
│ │ │ │ └── application.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ ├── old.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── disable-security/
│ │ ├── app/
│ │ │ ├── context.js
│ │ │ ├── controller/
│ │ │ │ ├── home.js
│ │ │ │ └── session.js
│ │ │ ├── router.js
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo.js
│ │ │ ├── foo.js
│ │ │ ├── old.js
│ │ │ └── third/
│ │ │ └── bar/
│ │ │ └── foo.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ ├── config.js
│ │ │ └── plugin.js
│ │ ├── mocks_data/
│ │ │ └── service/
│ │ │ ├── bar/
│ │ │ │ └── foo/
│ │ │ │ └── get/
│ │ │ │ └── foobar.js
│ │ │ └── foo/
│ │ │ └── get/
│ │ │ └── foobar.js
│ │ └── package.json
│ ├── error-framework/
│ │ ├── index.js
│ │ └── package.json
│ ├── failed-app/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── fooPlugin/
│ │ ├── app.js
│ │ ├── config/
│ │ │ ├── config.default.js
│ │ │ └── plugin.js
│ │ └── package.json
│ ├── get-app-failed/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── messenger-binding/
│ │ ├── agent.js
│ │ ├── app.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── plugin/
│ │ └── package.json
│ ├── plugin-bootstrap/
│ │ ├── package.json
│ │ └── test.js
│ ├── plugin_throw/
│ │ └── package.json
│ ├── request/
│ │ ├── app/
│ │ │ └── router.js
│ │ ├── config/
│ │ │ └── config.default.js
│ │ └── package.json
│ ├── server/
│ │ ├── app.js
│ │ └── package.json
│ ├── setup-app/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ ├── .setup.js
│ │ └── index.test.js
│ ├── tegg-app/
│ │ ├── app/
│ │ │ └── modules/
│ │ │ └── foo/
│ │ │ ├── LogService.ts
│ │ │ └── package.json
│ │ ├── app.js
│ │ ├── config/
│ │ │ ├── config.default.js
│ │ │ └── plugin.js
│ │ ├── package.json
│ │ ├── test/
│ │ │ ├── hooks.test.ts
│ │ │ ├── multi_mock_context.test.ts
│ │ │ ├── tegg.test.ts
│ │ │ └── tegg_context.test.ts
│ │ ├── tsconfig.json
│ │ └── typing.ts
│ ├── test-case-create-context-failed/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ ├── test-case-get-app-failed/
│ │ ├── config/
│ │ │ └── config.default.js
│ │ ├── package.json
│ │ └── test/
│ │ └── index.test.js
│ └── yadan_app/
│ ├── config/
│ │ └── config.default.js
│ └── package.json
├── format_options.test.js
├── index.test.ts
├── inject_ctx.test.js
├── mm.test.js
├── mock_agent_httpclient.test.js
├── mock_cluster_extend.test.js
├── mock_cluster_restore.test.js
├── mock_cluster_without_security_plugin.test.js
├── mock_context.test.js
├── mock_cookies.test.js
├── mock_csrf.test.js
├── mock_custom_loader.test.js
├── mock_env.test.js
├── mock_headers.test.js
├── mock_httpclient.test.js
├── mock_httpclient_next.test.js
├── mock_httpclient_next_h2.test.js
├── mock_request.test.js
├── mock_service.test.js
├── mock_service_async.test.js
├── mock_service_cluster.test.js
├── mock_session.test.js
├── parallel.test.js
├── parallel_hook.test.js
└── tsd.test.js
SYMBOL INDEX (229 symbols across 63 files)
FILE: app/extend/agent.js
method mockHttpclient (line 12) | mockHttpclient(...args) {
method mockAgent (line 24) | mockAgent() {
method mockAgentRestore (line 28) | async mockAgentRestore() {
FILE: app/extend/application.js
constant ORIGIN_TYPES (line 13) | const ORIGIN_TYPES = Symbol('egg-mock:originTypes');
constant BACKGROUND_TASKS (line 14) | const BACKGROUND_TASKS = Symbol('Application#backgroundTasks');
constant REUSED_CTX (line 15) | const REUSED_CTX = Symbol('Context#reusedInSuite');
method mockContext (line 39) | mockContext(data, options) {
method mockContextScope (line 76) | async mockContextScope(fn, data) {
method mockSession (line 90) | mockSession(data) {
method mockService (line 113) | mockService(service, methodName, fn) {
method mockServiceError (line 134) | mockServiceError(service, methodName, err) {
method _mockFn (line 145) | _mockFn(obj, name, data) {
method mockRequest (line 198) | mockRequest(req) {
method mockCookies (line 232) | mockCookies(cookies) {
method mockHeaders (line 257) | mockHeaders(headers) {
method mockCsrf (line 276) | mockCsrf() {
method mockHttpclient (line 288) | mockHttpclient(...args) {
method mockUrllib (line 295) | mockUrllib(...args) {
method mockAgent (line 305) | mockAgent() {
method mockAgentRestore (line 309) | async mockAgentRestore() {
method loadAgent (line 329) | loadAgent() {}
method mockEnv (line 337) | mockEnv(env) {
method httpRequest (line 349) | httpRequest() {
method mockLog (line 358) | mockLog(logger) {
method __checkExpectLog (line 377) | __checkExpectLog(expectOrNot, str, logger) {
method expectLog (line 411) | expectLog(str, logger) {
method notExpectLog (line 421) | notExpectLog(str, logger) {
method backgroundTasksFinished (line 425) | backgroundTasksFinished() {
method _backgroundTasks (line 440) | get _backgroundTasks() {
method _backgroundTasks (line 447) | set _backgroundTasks(tasks) {
function findHeaders (line 453) | function findHeaders(headers, key) {
FILE: bootstrap.js
method app (line 18) | get app() {
FILE: index.d.ts
type EggTest (line 9) | interface EggTest extends Test {
type Methods (line 14) | type Methods = 'get' | 'post' | 'delete' | 'del' | 'put' | 'head' | 'opt...
type BaseMockApplication (line 16) | interface BaseMockApplication<T, C> extends Application {
type ResultObject (line 85) | interface ResultObject {
type ResultFunction (line 94) | type ResultFunction = (url?: string, opts?: any) => ResultObject | strin...
type MockHttpClientResult (line 96) | type MockHttpClientResult = ResultObject | ResultFunction | string;
type MockOption (line 98) | interface MockOption {
type EnvType (line 130) | type EnvType = 'default' | 'test' | 'prod' | 'local' | 'unittest' | stri...
type LogLevel (line 131) | type LogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'NONE';
type MockApplication (line 133) | interface MockApplication extends BaseMockApplication<Application, Conte...
type EggMock (line 135) | interface EggMock extends MockMate {
FILE: index.js
function mock (line 15) | function mock(...args) {
method restore (line 23) | async restore() {
method env (line 59) | env(env) {
method consoleLevel (line 68) | consoleLevel(level) {
method home (line 73) | home(homePath) {
FILE: lib/app.js
constant INIT (line 18) | const INIT = Symbol('init');
constant APP_INIT (line 19) | const APP_INIT = Symbol('appInit');
constant BIND_EVENT (line 20) | const BIND_EVENT = Symbol('bindEvent');
constant INIT_ON_LISTENER (line 21) | const INIT_ON_LISTENER = Symbol('initOnListener');
constant INIT_ONCE_LISTENER (line 22) | const INIT_ONCE_LISTENER = Symbol('initOnceListener');
constant MESSENGER (line 23) | const MESSENGER = Symbol('messenger');
constant MOCK_APP_METHOD (line 24) | const MOCK_APP_METHOD = [
class MockApplication (line 35) | class MockApplication extends EventEmitter {
method constructor (line 36) | constructor(options) {
method [INIT] (line 59) | * [INIT]() {
method [BIND_EVENT] (line 115) | [BIND_EVENT]() {
method on (line 128) | on(...args) {
method once (line 139) | once(...args) {
method close (line 154) | close() {
method get (line 191) | get(target, prop) {
method set (line 200) | set(target, prop, value) {
method defineProperty (line 207) | defineProperty(target, prop, descriptor) {
method deleteProperty (line 215) | deleteProperty(target, prop) {
method getOwnPropertyDescriptor (line 223) | getOwnPropertyDescriptor(target, prop) {
method getPrototypeOf (line 229) | getPrototypeOf(target) {
function getProperty (line 240) | function getProperty(target, prop) {
function bindMessenger (line 249) | function bindMessenger(Application, agent) {
FILE: lib/cluster.js
class ClusterApplication (line 43) | class ClusterApplication extends Coffee {
method constructor (line 56) | constructor(options) {
method process (line 113) | get process() {
method callback (line 121) | callback() {
method url (line 130) | get url() {
method address (line 140) | address() {
method listen (line 151) | listen() {
method close (line 159) | close() {
method router (line 179) | get router() {
method mockLog (line 195) | mockLog(logger) {
method expectLog (line 208) | expectLog(str, logger) {
method notExpectLog (line 221) | notExpectLog(str, logger) {
method httpRequest (line 226) | httpRequest() {
method _callFunctionOnAppWorker (line 230) | _callFunctionOnAppWorker(method, args = [], property = undefined, need...
method get (line 315) | get(target, prop) {
FILE: lib/context.js
method runInBackground (line 17) | runInBackground(scope) {
FILE: lib/format_options.js
function getPluginName (line 81) | function getPluginName(pkgPath) {
FILE: lib/http_test.js
class EggTest (line 5) | class EggTest extends Test {
method unexpectHeader (line 16) | unexpectHeader(name, b) {
method expectHeader (line 38) | expectHeader(name, b) {
method _unexpectHeader (line 50) | _unexpectHeader(name, res) {
method _expectHeader (line 57) | _expectHeader(name, res) {
FILE: lib/inject_context.js
constant MOCHA_SUITE_APP (line 3) | const MOCHA_SUITE_APP = Symbol.for('mocha#suite#app');
function injectContext (line 11) | function injectContext(mocha) {
FILE: lib/mock_agent.js
constant APP_HTTPCLIENT_AGENT (line 26) | const APP_HTTPCLIENT_AGENT = Symbol('app.httpclient.agent');
method getAgent (line 30) | getAgent(app) {
method restore (line 49) | async restore() {
FILE: lib/mock_custom_loader.js
function addMethod (line 13) | function addMethod(loaderConfig) {
FILE: lib/mock_http_server.js
constant SERVER (line 4) | const SERVER = Symbol('http_server');
FILE: lib/mock_httpclient.js
function matchMethod (line 6) | function matchMethod(mockMethods, method) {
function matchUrl (line 9) | function matchUrl(mockUrl, url) {
function normalizeResult (line 15) | function normalizeResult(result) {
function _request (line 169) | async function _request(url, opt) {
FILE: lib/parallel/agent.js
class MockAgent (line 17) | class MockAgent extends Base {
method constructor (line 18) | constructor(options) {
method _init (line 32) | async _init() {
method [BIND_EVENT] (line 71) | [BIND_EVENT]() {
method on (line 84) | on(...args) {
method once (line 97) | once(...args) {
method close (line 114) | async close() {
FILE: lib/parallel/app.js
class MockApplication (line 17) | class MockApplication extends Base {
method constructor (line 18) | constructor(options) {
method _init (line 32) | async _init() {
method [BIND_EVENT] (line 67) | [BIND_EVENT]() {
method on (line 80) | on(...args) {
method once (line 93) | once(...args) {
method close (line 110) | async close() {
FILE: lib/parallel/util.js
constant MOCK_APP_METHOD (line 6) | const MOCK_APP_METHOD = [
constant INIT (line 14) | const INIT = Symbol('init');
constant APP_INIT (line 15) | const APP_INIT = Symbol('appInit');
constant BIND_EVENT (line 16) | const BIND_EVENT = Symbol('bindEvent');
constant INIT_ON_LISTENER (line 17) | const INIT_ON_LISTENER = Symbol('initOnListener');
constant INIT_ONCE_LISTENER (line 18) | const INIT_ONCE_LISTENER = Symbol('initOnceListener');
function proxyApp (line 20) | function proxyApp(app) {
FILE: lib/utils.js
method sleep (line 9) | async sleep(delay) {
method rimraf (line 13) | async rimraf(filepath) {
method rimrafSync (line 17) | rimrafSync(filepath) {
method getProperty (line 21) | getProperty(target, prop) {
method getEggOptions (line 28) | getEggOptions() {
FILE: register.js
method beforeAll (line 20) | async beforeAll() {
method afterEach (line 27) | async afterEach() {
method afterAll (line 35) | async afterAll() {
function findNodeJSMocha (line 51) | function findNodeJSMocha() {
FILE: test/app.test.js
method beforeInit (line 75) | beforeInit(instance) {
function call (line 133) | function call(method) {
FILE: test/app_proxy.test.js
method get (line 130) | get() {
method set (line 136) | set(prop) {
FILE: test/fixtures/agent-boot-error/agent.js
class CustomError (line 4) | class CustomError extends FrameworkBaseError {
method module (line 5) | get module() {
method configWillLoad (line 11) | configWillLoad() {
FILE: test/fixtures/agent-boot-ready-error/agent.js
class CustomError (line 4) | class CustomError extends FrameworkBaseError {
method module (line 5) | get module() {
method didLoad (line 11) | async didLoad() {
FILE: test/fixtures/agent/client.js
class Client (line 5) | class Client extends Base {
method constructor (line 6) | constructor() {
method subscribe (line 11) | subscribe(topic, listener) {
FILE: test/fixtures/app-boot-error/app.js
class CustomError (line 4) | class CustomError extends FrameworkBaseError {
method module (line 5) | get module() {
method configWillLoad (line 11) | configWillLoad() {
FILE: test/fixtures/app-boot-ready-error/app.js
class CustomError (line 4) | class CustomError extends FrameworkBaseError {
method module (line 5) | get module() {
method didLoad (line 11) | async didLoad() {
FILE: test/fixtures/app-proxy/app/extend/application.js
method getter (line 4) | get getter() {
method method (line 7) | method() {
method a (line 13) | get a() {
method a (line 16) | set a(x) {
FILE: test/fixtures/app-ready-failed/app.js
method didLoad (line 3) | async didLoad() {
FILE: test/fixtures/apps/app-throw/app/router.js
method toString (line 33) | toString() {
FILE: test/fixtures/apps/no-framework/plugin/a/app/extend/application.js
method mockEnv (line 4) | mockEnv() {
FILE: test/fixtures/bar/index.js
constant EGG_PATH (line 4) | const EGG_PATH = Symbol.for('egg#eggPath');
class BarApplication (line 6) | class BarApplication extends egg.Application {
method [EGG_PATH] (line 7) | get [EGG_PATH]() {
FILE: test/fixtures/chair/index.js
function startCluster (line 5) | function startCluster(options) {
FILE: test/fixtures/custom-loader/app/adapter/docker.js
class DockerAdapter (line 3) | class DockerAdapter {
method constructor (line 4) | constructor(app) {
method inspectDocker (line 8) | async inspectDocker() {
FILE: test/fixtures/custom-loader/app/controller/user.js
class UserController (line 3) | class UserController {
method constructor (line 4) | constructor(ctx) {
method get (line 9) | async get() {
FILE: test/fixtures/custom-loader/app/repository/user.js
class UserRepository (line 3) | class UserRepository {
method constructor (line 4) | constructor(ctx) {
method get (line 8) | async get() {
FILE: test/fixtures/demo-async/app/controller/home.js
class Home (line 4) | class Home extends app.Controller {
method testService (line 5) | async testService() {
FILE: test/fixtures/demo-async/app/service/bar/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | async get() {
FILE: test/fixtures/demo-async/app/service/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | async get() {
method getSync (line 9) | getSync() {
FILE: test/fixtures/demo-async/app/service/third/bar/foo.js
class Main (line 4) | class Main extends app.Service {
method get (line 5) | async get() {
FILE: test/fixtures/demo/app/context.js
method getResult (line 4) | getResult(result) {
FILE: test/fixtures/demo/app/extend/application.js
method mockDevice (line 4) | mockDevice(obj) {
method mockGenerator (line 9) | * mockGenerator(obj) {
method mockPromise (line 14) | mockPromise(obj) {
FILE: test/fixtures/demo/app/service/bar/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | * get() {
FILE: test/fixtures/demo/app/service/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | * get() {
method getSync (line 9) | getSync() {
FILE: test/fixtures/demo/app/service/third/bar/foo.js
class Main (line 4) | class Main extends app.Service {
method get (line 5) | * get() {
FILE: test/fixtures/demo_next/app/context.js
method getResult (line 4) | getResult(result) {
FILE: test/fixtures/demo_next/app/extend/application.js
method mockDevice (line 4) | mockDevice(obj) {
method mockGenerator (line 9) | * mockGenerator(obj) {
method mockPromise (line 14) | mockPromise(obj) {
FILE: test/fixtures/demo_next/app/service/bar/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | * get() {
FILE: test/fixtures/demo_next/app/service/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | * get() {
method getSync (line 9) | getSync() {
FILE: test/fixtures/demo_next/app/service/third/bar/foo.js
class Main (line 4) | class Main extends app.Service {
method get (line 5) | * get() {
FILE: test/fixtures/demo_next_h2/app/context.js
method getResult (line 4) | getResult(result) {
FILE: test/fixtures/demo_next_h2/app/extend/application.js
method mockDevice (line 4) | mockDevice(obj) {
method mockGenerator (line 9) | * mockGenerator(obj) {
method mockPromise (line 14) | mockPromise(obj) {
FILE: test/fixtures/demo_next_h2/app/service/bar/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | * get() {
FILE: test/fixtures/demo_next_h2/app/service/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | * get() {
method getSync (line 9) | getSync() {
FILE: test/fixtures/demo_next_h2/app/service/third/bar/foo.js
class Main (line 4) | class Main extends app.Service {
method get (line 5) | * get() {
FILE: test/fixtures/disable-security/app/context.js
method getResult (line 4) | getResult(result) {
FILE: test/fixtures/disable-security/app/service/bar/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | * get() {
FILE: test/fixtures/disable-security/app/service/foo.js
class Foo (line 4) | class Foo extends app.Service {
method get (line 5) | * get() {
method getSync (line 9) | getSync() {
FILE: test/fixtures/disable-security/app/service/third/bar/foo.js
class Main (line 4) | class Main extends app.Service {
method get (line 5) | * get() {
FILE: test/fixtures/error-framework/index.js
class Application (line 5) | class Application extends egg.Application {
method constructor (line 6) | constructor() {
FILE: test/fixtures/tegg-app/app/modules/foo/LogService.ts
type Tracer (line 3) | interface Tracer {
class LogService (line 10) | class LogService {
method getTracerId (line 14) | getTracerId() {
FILE: test/mock_agent_httpclient.test.js
function crtHttpclient (line 252) | function crtHttpclient(app) {
FILE: test/mock_env.test.js
function sleep (line 43) | function sleep(ms) {
Condensed preview — 283 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (333K chars).
[
{
"path": ".eslintrc",
"chars": 79,
"preview": "{\n \"extends\": \"eslint-config-egg\",\n \"globals\": {\n \"beforeAll\": true\n }\n}\n"
},
{
"path": ".github/workflows/nodejs.yml",
"chars": 341,
"preview": "name: CI\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n\njobs:\n Job:\n name: Node.js\n"
},
{
"path": ".github/workflows/pkg.pr.new.yml",
"chars": 442,
"preview": "name: Publish Any Commit\non: [push, pull_request]\n\njobs:\n build:\n runs-on: ubuntu-latest\n\n steps:\n - name: C"
},
{
"path": ".github/workflows/release.yml",
"chars": 258,
"preview": "name: Release\n\non:\n push:\n branches: [ master ]\n\njobs:\n release:\n name: Node.js\n uses: eggjs/github-actions/."
},
{
"path": ".gitignore",
"chars": 157,
"preview": "node_modules/\ncoverage/\nlogs/\n!test/fixtures/apps/app-not-clean/logs/keep\n!test/fixtures/yadan/node_modules\nrun/\n.vscode"
},
{
"path": "CHANGELOG.md",
"chars": 28186,
"preview": "# Changelog\n\n## [5.15.1](https://github.com/eggjs/egg-mock/compare/v5.15.0...v5.15.1) (2024-12-12)\n\n\n### Bug Fixes\n\n* tr"
},
{
"path": "LICENSE",
"chars": 1118,
"preview": "MIT License\n\nCopyright (c) 2017-present Alibaba Group Holding Limited and other contributors.\n\nPermission is hereby gran"
},
{
"path": "README.md",
"chars": 11162,
"preview": "# egg-mock\n\n[![NPM version][npm-image]][npm-url]\n[;\nconst mockHttpclient = require('../../lib/mock_httpclient');\nconst mockAgent = require('../../"
},
{
"path": "app/extend/application.js",
"chars": 11952,
"preview": "const debug = require('util').debuglog('egg-mock:application');\nconst mm = require('mm');\nconst http = require('http');\n"
},
{
"path": "app/middleware/cluster_app_mock.js",
"chars": 2552,
"preview": "const debug = require('util').debuglog('egg-mock:middleware:cluster_app_mock');\nconst is = require('is-type-of');\nconst "
},
{
"path": "app.js",
"chars": 321,
"preview": "'use strict';\n\nmodule.exports = app => {\n // make sure clusterAppMock position before securities\n const index = app.co"
},
{
"path": "bootstrap.d.ts",
"chars": 216,
"preview": "import * as assert from 'assert';\nimport { MockApplication, EggMock } from './';\n\nexport {\n assert\n}\nexport declare con"
},
{
"path": "bootstrap.js",
"chars": 600,
"preview": "const assert = require('assert');\nconst path = require('path');\nconst mock = require('./index').default;\nconst appHandle"
},
{
"path": "index.d.ts",
"chars": 3910,
"preview": "import { Application, Context, EggLogger } from 'egg';\nimport { MockMate } from 'mm';\nimport { Test } from 'supertest';\n"
},
{
"path": "index.js",
"chars": 2182,
"preview": "const mm = require('mm');\nconst cluster = require('./lib/cluster');\nconst app = require('./lib/app');\nconst mockAgent = "
},
{
"path": "index.test-d.ts",
"chars": 1849,
"preview": "import { expectType } from 'tsd';\nimport { Application, Context } from 'egg';\nimport { MockApplication, MockAgent, Resul"
},
{
"path": "lib/agent_handler.js",
"chars": 715,
"preview": "const debug = require('util').debuglog('egg-mock:lib:agent');\nconst Agent = require('./parallel/agent');\nconst { getEggO"
},
{
"path": "lib/app.js",
"chars": 8929,
"preview": "const debug = require('util').debuglog('egg-mock:lib:app');\nconst os = require('os');\nconst path = require('path');\ncons"
},
{
"path": "lib/app_handler.js",
"chars": 1502,
"preview": "const debug = require('util').debuglog('egg-mock:bootstrap:app_handler');\nconst mockParallelApp = require('./parallel/ap"
},
{
"path": "lib/cluster.js",
"chars": 8756,
"preview": "const debug = require('util').debuglog('egg-mock:cluster');\nconst path = require('path');\nconst os = require('os');\ncons"
},
{
"path": "lib/context.js",
"chars": 635,
"preview": "'use strict';\n\n// try to use eggUtils.getCalleeFromStack\n// ignore it if egg-core module not found\nlet eggUtils;\ntry {\n "
},
{
"path": "lib/format_options.js",
"chars": 2413,
"preview": "const debug = require('util').debuglog('mm');\nconst path = require('path');\nconst mm = require('mm');\nconst utils = requ"
},
{
"path": "lib/http_test.js",
"chars": 1266,
"preview": "'use strict';\n\nconst Test = require('supertest').Test;\n\nclass EggTest extends Test {\n /**\n * Unexpectations:\n *\n "
},
{
"path": "lib/inject_context.js",
"chars": 3466,
"preview": "const assert = require('assert');\nconst debug = require('util').debuglog('egg-mock:inject_context');\nconst MOCHA_SUITE_A"
},
{
"path": "lib/mock_agent.js",
"chars": 1867,
"preview": "const { debuglog } = require('util');\nlet { MockAgent, setGlobalDispatcher, getGlobalDispatcher } = require('urllib');\ni"
},
{
"path": "lib/mock_custom_loader.js",
"chars": 1019,
"preview": "'use strict';\n\nmodule.exports = app => {\n const customLoader = app.config.customLoader;\n if (!customLoader) return;\n\n "
},
{
"path": "lib/mock_http_server.js",
"chars": 491,
"preview": "'use strict';\n\nconst http = require('http');\nconst SERVER = Symbol('http_server');\n\nmodule.exports = app => {\n let serv"
},
{
"path": "lib/mock_httpclient.js",
"chars": 7049,
"preview": "const mm = require('mm');\nconst extend = require('extend2');\nconst is = require('is-type-of');\nconst mockAgent = require"
},
{
"path": "lib/parallel/agent.js",
"chars": 3523,
"preview": "const debug = require('util').debuglog('egg-mock:lib:parallel:agent');\nconst path = require('path');\nconst Base = requir"
},
{
"path": "lib/parallel/agent_register.js",
"chars": 155,
"preview": "console.warn('[deprecated] use `egg-mock/register.js` instead of `egg-mock/lib/parallel/agent_register.js`');\n\nmodule.ex"
},
{
"path": "lib/parallel/app.js",
"chars": 3450,
"preview": "const debug = require('util').debuglog('egg-mock:lib:parallel:app');\nconst Base = require('sdk-base');\nconst context = r"
},
{
"path": "lib/parallel/util.js",
"chars": 2795,
"preview": "const debug = require('util').debuglog('egg-mock:lib:parallel:util');\nconst ConsoleLogger = require('egg-logger').EggCon"
},
{
"path": "lib/prerequire.js",
"chars": 685,
"preview": "const debug = require('util').debuglog('egg-mock:prerequire');\nconst path = require('path');\nconst { existsSync } = requ"
},
{
"path": "lib/request_call_function.js",
"chars": 1162,
"preview": "const httpclient = require('urllib');\n\nconst { port, method, args, property, needResult } = JSON.parse(process.argv[2]);"
},
{
"path": "lib/start-cluster",
"chars": 184,
"preview": "#!/usr/bin/env node\n\nif (process.env.EGG_BIN_PREREQUIRE) require('./prerequire');\n\nconst options = JSON.parse(process.ar"
},
{
"path": "lib/supertest.js",
"chars": 1007,
"preview": "'use strict';\n\nconst methods = require('methods');\nconst EggTest = require('./http_test');\nconst mockHttpServer = requir"
},
{
"path": "lib/tmp/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "lib/utils.js",
"chars": 926,
"preview": "const util = require('util');\nconst { rm } = require('fs/promises');\nconst { rmSync } = require('fs');\nconst is = requir"
},
{
"path": "package.json",
"chars": 2102,
"preview": "{\n \"name\": \"egg-mock\",\n \"version\": \"5.15.2\",\n \"eggPlugin\": {\n \"name\": \"egg-mock\"\n },\n \"description\": \"mock serve"
},
{
"path": "register.js",
"chars": 1819,
"preview": "const debug = require('util').debuglog('egg-mock:register');\nconst mock = require('./index').default;\nconst agentHandler"
},
{
"path": "test/agent.test.js",
"chars": 2276,
"preview": "'use strict';\n\nconst mm = require('..');\nconst fs = require('fs');\nconst path = require('path');\nconst { rimraf } = requ"
},
{
"path": "test/app/middleware/cluster_app_mock.test.js",
"chars": 1901,
"preview": "'use strict';\n\nconst assert = require('assert');\nconst mm = require('../../..');\n\ndescribe('test/app/middleware/cluster_"
},
{
"path": "test/app.test.js",
"chars": 12057,
"preview": "'use strict';\n\nconst request = require('supertest');\nconst path = require('path');\nconst assert = require('assert');\ncon"
},
{
"path": "test/app_event.test.js",
"chars": 2441,
"preview": "const path = require('path');\nconst request = require('supertest');\nconst pedding = require('pedding');\nconst assert = r"
},
{
"path": "test/app_proxy.test.js",
"chars": 7361,
"preview": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\nconst fixtures "
},
{
"path": "test/bootstrap-plugin.test.js",
"chars": 559,
"preview": "'use strict';\n\nconst path = require('path');\nconst coffee = require('coffee');\nconst mock = require('mm');\n\ndescribe('te"
},
{
"path": "test/bootstrap.test.js",
"chars": 2846,
"preview": "'use strict';\n\nconst path = require('path');\nconst baseDir = process.env.EGG_BASE_DIR = path.join(__dirname, './fixtures"
},
{
"path": "test/cluster.test.js",
"chars": 6626,
"preview": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst request = require('supertest');\ncon"
},
{
"path": "test/ctx.test.js",
"chars": 2106,
"preview": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\n\nconst fixtures"
},
{
"path": "test/fixtures/agent/agent.js",
"chars": 373,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst Client = require('./client');\n\nmodule.exports = agent => {"
},
{
"path": "test/fixtures/agent/app.js",
"chars": 355,
"preview": "'use strict';\n\nconst fs = require('fs');\nconst path = require('path');\nconst Client = require('./client');\n\nmodule.expor"
},
{
"path": "test/fixtures/agent/client.js",
"chars": 242,
"preview": "'use strict';\n\nconst Base = require('sdk-base');\n\nclass Client extends Base {\n constructor() {\n super();\n this.re"
},
{
"path": "test/fixtures/agent/config/config.default.js",
"chars": 52,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n};\n"
},
{
"path": "test/fixtures/agent/package.json",
"chars": 21,
"preview": "{\n \"name\": \"demo\"\n}\n"
},
{
"path": "test/fixtures/agent-boot-error/agent.js",
"chars": 265,
"preview": "'use strict';\n\nconst { FrameworkBaseError } = require('egg-errors');\nclass CustomError extends FrameworkBaseError {\n ge"
},
{
"path": "test/fixtures/agent-boot-error/package.json",
"chars": 33,
"preview": "{\n \"name\": \"agent-boot-error\"\n}\n"
},
{
"path": "test/fixtures/agent-boot-ready-error/agent.js",
"chars": 264,
"preview": "'use strict';\n\nconst { FrameworkBaseError } = require('egg-errors');\nclass CustomError extends FrameworkBaseError {\n ge"
},
{
"path": "test/fixtures/agent-boot-ready-error/package.json",
"chars": 39,
"preview": "{\n \"name\": \"agent-boot-ready-error\"\n}\n"
},
{
"path": "test/fixtures/app/app/router.js",
"chars": 1519,
"preview": "const { sleep } = require('../../../../lib/utils');\n\nmodule.exports = app => {\n app.get('/', async ctx => {\n ctx.bod"
},
{
"path": "test/fixtures/app/app.js",
"chars": 147,
"preview": "'use strict';\n\nmodule.exports = app => {\n app.on('server', server => {\n app.serverKeepAliveTimeout = server.keepAliv"
},
{
"path": "test/fixtures/app/config/config.default.js",
"chars": 52,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n};\n"
},
{
"path": "test/fixtures/app/package.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "test/fixtures/app-boot-error/app.js",
"chars": 265,
"preview": "'use strict';\n\nconst { FrameworkBaseError } = require('egg-errors');\nclass CustomError extends FrameworkBaseError {\n ge"
},
{
"path": "test/fixtures/app-boot-error/package.json",
"chars": 31,
"preview": "{\n \"name\": \"app-boot-error\"\n}\n"
},
{
"path": "test/fixtures/app-boot-ready-error/app.js",
"chars": 264,
"preview": "'use strict';\n\nconst { FrameworkBaseError } = require('egg-errors');\nclass CustomError extends FrameworkBaseError {\n ge"
},
{
"path": "test/fixtures/app-boot-ready-error/package.json",
"chars": 37,
"preview": "{\n \"name\": \"app-boot-ready-error\"\n}\n"
},
{
"path": "test/fixtures/app-event/agent.js",
"chars": 105,
"preview": "'use strict';\n\nmodule.exports = app => {\n app.ready(() => {\n app.emit('agentInstantiated');\n });\n};\n"
},
{
"path": "test/fixtures/app-event/app/router.js",
"chars": 153,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n app.get('/event', function* () {\n this.app.emit('eventByRequest');\n"
},
{
"path": "test/fixtures/app-event/app.js",
"chars": 338,
"preview": "'use strict';\n\nconst { sleep } = require('../../../lib/utils');\n\nmodule.exports = app => {\n app.ready(() => {\n // af"
},
{
"path": "test/fixtures/app-event/config/config.default.js",
"chars": 52,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n};\n"
},
{
"path": "test/fixtures/app-event/package.json",
"chars": 26,
"preview": "{\n \"name\": \"app-event\"\n}\n"
},
{
"path": "test/fixtures/app-fail/app/router.js",
"chars": 46,
"preview": "'use strict';\n\nthrow new Error('load error');\n"
},
{
"path": "test/fixtures/app-fail/config/config.default.js",
"chars": 52,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n};\n"
},
{
"path": "test/fixtures/app-fail/package.json",
"chars": 25,
"preview": "{\n \"name\": \"egg-mock\"\n}\n"
},
{
"path": "test/fixtures/app-proxy/app/extend/application.js",
"chars": 223,
"preview": "'use strict';\n\nmodule.exports = {\n get getter() {\n return 'getter';\n },\n method() {\n return 'method';\n },\n pr"
},
{
"path": "test/fixtures/app-proxy/config/config.default.js",
"chars": 52,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n};\n"
},
{
"path": "test/fixtures/app-proxy/package.json",
"chars": 26,
"preview": "{\n \"name\": \"app-proxy\"\n}\n"
},
{
"path": "test/fixtures/app-proxy-ready/agent.js",
"chars": 203,
"preview": "'use strict';\n\nconst { sleep } = require('../../../lib/utils');\n\nmodule.exports = app => {\n // set timeout let testcase"
},
{
"path": "test/fixtures/app-proxy-ready/app.js",
"chars": 160,
"preview": "'use strict';\n\nmodule.exports = app => {\n app.emit('eventOnReady');\n app.emit('eventOnReady');\n app.emit('eventOnceRe"
},
{
"path": "test/fixtures/app-proxy-ready/config/config.default.js",
"chars": 52,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n};\n"
},
{
"path": "test/fixtures/app-proxy-ready/package.json",
"chars": 32,
"preview": "{\n \"name\": \"app-proxy-ready\"\n}\n"
},
{
"path": "test/fixtures/app-ready-failed/app.js",
"chars": 107,
"preview": "module.exports = class AppHook {\n\n async didLoad() {\n throw new Error('mock app ready failed');\n }\n};\n"
},
{
"path": "test/fixtures/app-ready-failed/config/config.default.js",
"chars": 52,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n};\n"
},
{
"path": "test/fixtures/app-ready-failed/package.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "test/fixtures/app-ready-failed/test/index.test.js",
"chars": 201,
"preview": "const assert = require('assert');\nconst { app } = require('../../../../bootstrap');\ndescribe('test for app ready failed'"
},
{
"path": "test/fixtures/apps/app-not-clean/config/config.default.js",
"chars": 52,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n};\n"
},
{
"path": "test/fixtures/apps/app-not-clean/logs/keep",
"chars": 0,
"preview": ""
},
{
"path": "test/fixtures/apps/app-not-clean/package.json",
"chars": 30,
"preview": "{\n \"name\": \"app-not-clean\"\n}\n"
},
{
"path": "test/fixtures/apps/app-throw/app/router.js",
"chars": 927,
"preview": "'use strict';\n\nmodule.exports = app => {\n app.get('/throw', function* () {\n this.body = 'foo';\n setTimeout(() => "
},
{
"path": "test/fixtures/apps/app-throw/config/config.default.js",
"chars": 42,
"preview": "'use strict';\n\nexports.keys = 'test key';\n"
},
{
"path": "test/fixtures/apps/app-throw/config/config.unittest.js",
"chars": 61,
"preview": "'use strict';\n\nexports.logger = {\n consoleLevel: 'NONE',\n};\n"
},
{
"path": "test/fixtures/apps/app-throw/package.json",
"chars": 26,
"preview": "{\n \"name\": \"app-throw\"\n}\n"
},
{
"path": "test/fixtures/apps/barapp/app/controller/home.js",
"chars": 137,
"preview": "'use strict';\n\nmodule.exports = function* () {\n this.body = {\n foo: this.app.config.foo,\n foobar: this.app.config"
},
{
"path": "test/fixtures/apps/barapp/app/router.js",
"chars": 88,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n app.get('/', app.controller.home);\n};\n"
},
{
"path": "test/fixtures/apps/barapp/config/config.default.js",
"chars": 59,
"preview": "'use strict';\n\nexports.foo = 'bar';\n\nexports.keys = '123';\n"
},
{
"path": "test/fixtures/apps/barapp/package.json",
"chars": 23,
"preview": "{\n \"name\": \"barapp\"\n}\n"
},
{
"path": "test/fixtures/apps/env-app/config/config.default.js",
"chars": 181,
"preview": "'use strict';\n\nexports.fakeplugin = {\n foo: 'bar-default',\n};\n\nexports.logger = {\n consoleLevel: 'NONE',\n};\n\nexports.d"
},
{
"path": "test/fixtures/apps/env-app/config/config.local.js",
"chars": 62,
"preview": "'use strict';\n\nexports.development = {\n fastReady: false,\n};\n"
},
{
"path": "test/fixtures/apps/env-app/config/config.prod.js",
"chars": 60,
"preview": "'use strict';\n\nexports.fakeplugin = {\n foo: 'bar-prod',\n};\n"
},
{
"path": "test/fixtures/apps/env-app/config/config.test.js",
"chars": 60,
"preview": "'use strict';\n\nexports.fakeplugin = {\n foo: 'bar-test',\n};\n"
},
{
"path": "test/fixtures/apps/env-app/config/config.unittest.js",
"chars": 64,
"preview": "'use strict';\n\nexports.fakeplugin = {\n foo: 'bar-unittest',\n};\n"
},
{
"path": "test/fixtures/apps/env-app/package.json",
"chars": 24,
"preview": "{\n \"name\": \"env-app\"\n}\n"
},
{
"path": "test/fixtures/apps/foo/app/router.js",
"chars": 144,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n app.get('/', function* () {\n this.body = {\n fooPlugin: app.foo"
},
{
"path": "test/fixtures/apps/foo/config/config.default.js",
"chars": 37,
"preview": "'use strict';\n\nexports.keys = '123';\n"
},
{
"path": "test/fixtures/apps/foo/package.json",
"chars": 20,
"preview": "{\n \"name\": \"foo\"\n}\n"
},
{
"path": "test/fixtures/apps/mock_cookies/app/router.js",
"chars": 265,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n app.get('/', function* () {\n this.body = {\n cookieValue: this."
},
{
"path": "test/fixtures/apps/mock_cookies/config/config.default.js",
"chars": 37,
"preview": "'use strict';\n\nexports.keys = '123';\n"
},
{
"path": "test/fixtures/apps/mock_cookies/package.json",
"chars": 28,
"preview": "{\n \"name\": \"mockCookies\"\n}\n"
},
{
"path": "test/fixtures/apps/mockhome/config/config.default.js",
"chars": 37,
"preview": "'use strict';\n\nexports.keys = '123';\n"
},
{
"path": "test/fixtures/apps/mockhome/package.json",
"chars": 25,
"preview": "{\n \"name\": \"mockhome\"\n}\n"
},
{
"path": "test/fixtures/apps/no-framework/config/plugin.js",
"chars": 145,
"preview": "'use strict';\n\nconst path = require('path');\n\nmodule.exports = {\n a: {\n enable: true,\n path: path.join(__dirname,"
},
{
"path": "test/fixtures/apps/no-framework/package.json",
"chars": 29,
"preview": "{\n \"name\": \"no-framework\"\n}\n"
},
{
"path": "test/fixtures/apps/no-framework/plugin/a/app/extend/application.js",
"chars": 98,
"preview": "'use strict';\n\nmodule.exports = {\n mockEnv() {\n this.config.env = 'mocked by plugin';\n },\n};\n"
},
{
"path": "test/fixtures/apps/no-framework/plugin/a/package.json",
"chars": 87,
"preview": "{\n \"eggPlugin\": {\n \"name\": \"a\",\n \"dependencies\": [\n \"egg-mock\"\n ]\n }\n}\n"
},
{
"path": "test/fixtures/apps/parallel-test/package.json",
"chars": 20,
"preview": "{\n \"name\": \"foo\"\n}\n"
},
{
"path": "test/fixtures/apps/parallel-test/test/a.test.js",
"chars": 222,
"preview": "const mm = require('../../../../../');\nconst assert = require('assert');\n\ndescribe('test/parallel_a.test.js', () => {\n "
},
{
"path": "test/fixtures/apps/parallel-test/test/b.test.js",
"chars": 222,
"preview": "const mm = require('../../../../../');\nconst assert = require('assert');\n\ndescribe('test/parallel_b.test.js', () => {\n "
},
{
"path": "test/fixtures/apps/parallel-test/test/c.test.js",
"chars": 143,
"preview": "const assert = require('assert');\n\ndescribe('test/parallel_a.test.js', () => {\n it('should work', () => {\n assert(!g"
},
{
"path": "test/fixtures/bar/config/config.default.js",
"chars": 62,
"preview": "'use strict';\n\nexports.foobar = 'bar';\n\nexports.keys = '123';\n"
},
{
"path": "test/fixtures/bar/index.js",
"chars": 252,
"preview": "'use strict';\n\nconst egg = require('egg');\nconst EGG_PATH = Symbol.for('egg#eggPath');\n\nclass BarApplication extends egg"
},
{
"path": "test/fixtures/bar/package.json",
"chars": 42,
"preview": "{\n \"name\": \"bar\",\n \"version\": \"1.0.0\"\n}\n"
},
{
"path": "test/fixtures/cache/config.default.js",
"chars": 37,
"preview": "'use strict';\n\nexports.keys = '123';\n"
},
{
"path": "test/fixtures/cache/package.json",
"chars": 22,
"preview": "{\n \"name\": \"cache\"\n}\n"
},
{
"path": "test/fixtures/chair/index.js",
"chars": 266,
"preview": "'use strict';\n\nconst egg = require('egg');\n\nfunction startCluster(options) {\n // print for the testcase that will asser"
},
{
"path": "test/fixtures/chair/package.json",
"chars": 22,
"preview": "{\n \"name\": \"chair\"\n}\n"
},
{
"path": "test/fixtures/create-context-failed/config/config.default.js",
"chars": 52,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n};\n"
},
{
"path": "test/fixtures/create-context-failed/package.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "test/fixtures/create-context-failed/test/index.test.js",
"chars": 445,
"preview": "const { setGetAppCallback } = require('../../../..');\n\nsetGetAppCallback(() => {\n return {\n ready: async () => {\n "
},
{
"path": "test/fixtures/custom-loader/app/adapter/docker.js",
"chars": 170,
"preview": "'use strict';\n\nclass DockerAdapter {\n constructor(app) {\n this.app = app;\n }\n\n async inspectDocker() {\n return "
},
{
"path": "test/fixtures/custom-loader/app/controller/user.js",
"chars": 311,
"preview": "'use strict';\n\nclass UserController {\n constructor(ctx) {\n this.ctx = ctx;\n this.app = ctx.app;\n }\n\n async get("
},
{
"path": "test/fixtures/custom-loader/app/repository/user.js",
"chars": 174,
"preview": "'use strict';\n\nclass UserRepository {\n constructor(ctx) {\n this.ctx = ctx;\n }\n\n async get() {\n return this.ctx."
},
{
"path": "test/fixtures/custom-loader/app/router.js",
"chars": 103,
"preview": "'use strict';\n\nmodule.exports = app => {\n app.router.get('/users/:name', app.controller.user.get);\n};\n"
},
{
"path": "test/fixtures/custom-loader/config/config.default.js",
"chars": 298,
"preview": "'use strict';\n\nmodule.exports = {\n keys: '123',\n customLoader: {\n adapter: {\n directory: 'app/adapter',\n "
},
{
"path": "test/fixtures/custom-loader/package.json",
"chars": 30,
"preview": "{\n \"name\": \"custom-loader\"\n}\n"
},
{
"path": "test/fixtures/custom_egg/package.json",
"chars": 23,
"preview": "{\n \"name\": \"custom\"\n}\n"
},
{
"path": "test/fixtures/demo/app/context.js",
"chars": 104,
"preview": "'use strict';\n\nmodule.exports = {\n getResult(result) {\n return {\n body: result,\n };\n },\n};\n"
},
{
"path": "test/fixtures/demo/app/controller/file.js",
"chars": 496,
"preview": "const assert = require('assert');\n\nmodule.exports = app => {\n return async function file(ctx) {\n const ctxFromStorag"
},
{
"path": "test/fixtures/demo/app/controller/home.js",
"chars": 2015,
"preview": "'use strict';\n\nexports.get = function* () {\n this.body = {\n cookieValue: this.getCookie('foo') || undefined,\n coo"
},
{
"path": "test/fixtures/demo/app/controller/session.js",
"chars": 101,
"preview": "'use strict';\n\nmodule.exports = function* () {\n this.session.save();\n this.body = this.session;\n};\n"
},
{
"path": "test/fixtures/demo/app/controller/user.js",
"chars": 203,
"preview": "exports.get = function* () {\n this.set('x-request-url', this.url);\n this.body = this.user;\n};\n\nexports.post = function"
},
{
"path": "test/fixtures/demo/app/extend/application.js",
"chars": 248,
"preview": "'use strict';\n\nmodule.exports = {\n mockDevice(obj) {\n obj.mock = true;\n return obj;\n },\n\n * mockGenerator(obj) "
},
{
"path": "test/fixtures/demo/app/router.js",
"chars": 831,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n app.get('home', '/', app.controller.home.get);\n app.get('/hello', app"
},
{
"path": "test/fixtures/demo/app/service/bar/foo.js",
"chars": 144,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Foo extends app.Service {\n * get() {\n return 'bar';\n "
},
{
"path": "test/fixtures/demo/app/service/foo.js",
"chars": 187,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Foo extends app.Service {\n * get() {\n return 'bar';\n "
},
{
"path": "test/fixtures/demo/app/service/old.js",
"chars": 119,
"preview": "'use strict';\n\nmodule.exports = () => {\n exports.test = function* () {\n return 'hello';\n };\n\n return exports;\n};\n"
},
{
"path": "test/fixtures/demo/app/service/third/bar/foo.js",
"chars": 148,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Main extends app.Service {\n * get() {\n return 'third';\n "
},
{
"path": "test/fixtures/demo/app.js",
"chars": 49,
"preview": "'use strict';\n\nmodule.exports = function() {\n\n};\n"
},
{
"path": "test/fixtures/demo/config/config.js",
"chars": 134,
"preview": "'use strict';\n\nmodule.exports = {\n urllib: {\n keepAlive: false,\n },\n logger: {\n consoleLevel: 'NONE',\n },\n ke"
},
{
"path": "test/fixtures/demo/mocks_data/service/bar/foo/get/foobar.js",
"chars": 42,
"preview": "'use strict';\n\nmodule.exports = 'foobar';\n"
},
{
"path": "test/fixtures/demo/mocks_data/service/foo/get/foobar.js",
"chars": 42,
"preview": "'use strict';\n\nmodule.exports = 'foobar';\n"
},
{
"path": "test/fixtures/demo/package.json",
"chars": 21,
"preview": "{\n \"name\": \"demo\"\n}\n"
},
{
"path": "test/fixtures/demo-async/app/controller/home.js",
"chars": 370,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Home extends app.Controller {\n async testService() {\n th"
},
{
"path": "test/fixtures/demo-async/app/router.js",
"chars": 107,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n app.get('/service', app.controller.home.testService);\n};\n"
},
{
"path": "test/fixtures/demo-async/app/service/bar/foo.js",
"chars": 148,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Foo extends app.Service {\n async get() {\n return 'bar';\n"
},
{
"path": "test/fixtures/demo-async/app/service/foo.js",
"chars": 191,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Foo extends app.Service {\n async get() {\n return 'bar';\n"
},
{
"path": "test/fixtures/demo-async/app/service/third/bar/foo.js",
"chars": 152,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Main extends app.Service {\n async get() {\n return 'third"
},
{
"path": "test/fixtures/demo-async/app.js",
"chars": 49,
"preview": "'use strict';\n\nmodule.exports = function() {\n\n};\n"
},
{
"path": "test/fixtures/demo-async/config/config.js",
"chars": 134,
"preview": "'use strict';\n\nmodule.exports = {\n urllib: {\n keepAlive: false,\n },\n logger: {\n consoleLevel: 'NONE',\n },\n ke"
},
{
"path": "test/fixtures/demo-async/mocks_data/service/bar/foo/get/foobar.js",
"chars": 42,
"preview": "'use strict';\n\nmodule.exports = 'foobar';\n"
},
{
"path": "test/fixtures/demo-async/mocks_data/service/foo/get/foobar.js",
"chars": 42,
"preview": "'use strict';\n\nmodule.exports = 'foobar';\n"
},
{
"path": "test/fixtures/demo-async/package.json",
"chars": 27,
"preview": "{\n \"name\": \"demo-async\"\n}\n"
},
{
"path": "test/fixtures/demo_next/app/context.js",
"chars": 104,
"preview": "'use strict';\n\nmodule.exports = {\n getResult(result) {\n return {\n body: result,\n };\n },\n};\n"
},
{
"path": "test/fixtures/demo_next/app/controller/file.js",
"chars": 212,
"preview": "'use strict';\n\nmodule.exports = function* () {\n const stream = yield this.getFileStream();\n const fields = stream.fiel"
},
{
"path": "test/fixtures/demo_next/app/controller/home.js",
"chars": 2508,
"preview": "'use strict';\n\nexports.get = function* () {\n this.body = {\n cookieValue: this.getCookie('foo') || undefined,\n coo"
},
{
"path": "test/fixtures/demo_next/app/controller/session.js",
"chars": 101,
"preview": "'use strict';\n\nmodule.exports = function* () {\n this.session.save();\n this.body = this.session;\n};\n"
},
{
"path": "test/fixtures/demo_next/app/controller/user.js",
"chars": 179,
"preview": "'use strict';\n\nexports.get = function* () {\n this.body = this.user;\n};\n\nexports.post = function* () {\n this.body = {\n "
},
{
"path": "test/fixtures/demo_next/app/extend/application.js",
"chars": 248,
"preview": "'use strict';\n\nmodule.exports = {\n mockDevice(obj) {\n obj.mock = true;\n return obj;\n },\n\n * mockGenerator(obj) "
},
{
"path": "test/fixtures/demo_next/app/router.js",
"chars": 969,
"preview": "module.exports = app => {\n app.get('home', '/', app.controller.home.get);\n app.get('/hello', app.controller.home.hello"
},
{
"path": "test/fixtures/demo_next/app/service/bar/foo.js",
"chars": 144,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Foo extends app.Service {\n * get() {\n return 'bar';\n "
},
{
"path": "test/fixtures/demo_next/app/service/foo.js",
"chars": 187,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Foo extends app.Service {\n * get() {\n return 'bar';\n "
},
{
"path": "test/fixtures/demo_next/app/service/old.js",
"chars": 119,
"preview": "'use strict';\n\nmodule.exports = () => {\n exports.test = function* () {\n return 'hello';\n };\n\n return exports;\n};\n"
},
{
"path": "test/fixtures/demo_next/app/service/third/bar/foo.js",
"chars": 148,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Main extends app.Service {\n * get() {\n return 'third';\n "
},
{
"path": "test/fixtures/demo_next/app.js",
"chars": 49,
"preview": "'use strict';\n\nmodule.exports = function() {\n\n};\n"
},
{
"path": "test/fixtures/demo_next/config/config.js",
"chars": 172,
"preview": "module.exports = {\n httpclient: {\n useHttpClientNext: true,\n request: {\n timing: true,\n },\n },\n logger:"
},
{
"path": "test/fixtures/demo_next/mocks_data/service/bar/foo/get/foobar.js",
"chars": 42,
"preview": "'use strict';\n\nmodule.exports = 'foobar';\n"
},
{
"path": "test/fixtures/demo_next/mocks_data/service/foo/get/foobar.js",
"chars": 42,
"preview": "'use strict';\n\nmodule.exports = 'foobar';\n"
},
{
"path": "test/fixtures/demo_next/package.json",
"chars": 21,
"preview": "{\n \"name\": \"demo\"\n}\n"
},
{
"path": "test/fixtures/demo_next_h2/app/context.js",
"chars": 104,
"preview": "'use strict';\n\nmodule.exports = {\n getResult(result) {\n return {\n body: result,\n };\n },\n};\n"
},
{
"path": "test/fixtures/demo_next_h2/app/controller/file.js",
"chars": 212,
"preview": "'use strict';\n\nmodule.exports = function* () {\n const stream = yield this.getFileStream();\n const fields = stream.fiel"
},
{
"path": "test/fixtures/demo_next_h2/app/controller/home.js",
"chars": 2508,
"preview": "'use strict';\n\nexports.get = function* () {\n this.body = {\n cookieValue: this.getCookie('foo') || undefined,\n coo"
},
{
"path": "test/fixtures/demo_next_h2/app/controller/session.js",
"chars": 101,
"preview": "'use strict';\n\nmodule.exports = function* () {\n this.session.save();\n this.body = this.session;\n};\n"
},
{
"path": "test/fixtures/demo_next_h2/app/controller/user.js",
"chars": 179,
"preview": "'use strict';\n\nexports.get = function* () {\n this.body = this.user;\n};\n\nexports.post = function* () {\n this.body = {\n "
},
{
"path": "test/fixtures/demo_next_h2/app/extend/application.js",
"chars": 248,
"preview": "'use strict';\n\nmodule.exports = {\n mockDevice(obj) {\n obj.mock = true;\n return obj;\n },\n\n * mockGenerator(obj) "
},
{
"path": "test/fixtures/demo_next_h2/app/router.js",
"chars": 969,
"preview": "module.exports = app => {\n app.get('home', '/', app.controller.home.get);\n app.get('/hello', app.controller.home.hello"
},
{
"path": "test/fixtures/demo_next_h2/app/service/bar/foo.js",
"chars": 144,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Foo extends app.Service {\n * get() {\n return 'bar';\n "
},
{
"path": "test/fixtures/demo_next_h2/app/service/foo.js",
"chars": 187,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Foo extends app.Service {\n * get() {\n return 'bar';\n "
},
{
"path": "test/fixtures/demo_next_h2/app/service/old.js",
"chars": 119,
"preview": "'use strict';\n\nmodule.exports = () => {\n exports.test = function* () {\n return 'hello';\n };\n\n return exports;\n};\n"
},
{
"path": "test/fixtures/demo_next_h2/app/service/third/bar/foo.js",
"chars": 148,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Main extends app.Service {\n * get() {\n return 'third';\n "
},
{
"path": "test/fixtures/demo_next_h2/app.js",
"chars": 49,
"preview": "'use strict';\n\nmodule.exports = function() {\n\n};\n"
},
{
"path": "test/fixtures/demo_next_h2/config/config.js",
"chars": 191,
"preview": "module.exports = {\n httpclient: {\n useHttpClientNext: true,\n allowH2: true,\n request: {\n timing: true,\n "
},
{
"path": "test/fixtures/demo_next_h2/mocks_data/service/bar/foo/get/foobar.js",
"chars": 42,
"preview": "'use strict';\n\nmodule.exports = 'foobar';\n"
},
{
"path": "test/fixtures/demo_next_h2/mocks_data/service/foo/get/foobar.js",
"chars": 42,
"preview": "'use strict';\n\nmodule.exports = 'foobar';\n"
},
{
"path": "test/fixtures/demo_next_h2/package.json",
"chars": 21,
"preview": "{\n \"name\": \"demo\"\n}\n"
},
{
"path": "test/fixtures/disable-security/app/context.js",
"chars": 104,
"preview": "'use strict';\n\nmodule.exports = {\n getResult(result) {\n return {\n body: result,\n };\n },\n};\n"
},
{
"path": "test/fixtures/disable-security/app/controller/home.js",
"chars": 1675,
"preview": "'use strict';\n\nexports.get = function* () {\n this.body = {\n cookieValue: this.getCookie('foo') || undefined,\n coo"
},
{
"path": "test/fixtures/disable-security/app/controller/session.js",
"chars": 78,
"preview": "'use strict';\n\nmodule.exports = function* () {\n this.body = this.session;\n};\n"
},
{
"path": "test/fixtures/disable-security/app/router.js",
"chars": 622,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n app.get('/', app.controller.home.get);\n app.get('/hello', app.control"
},
{
"path": "test/fixtures/disable-security/app/service/bar/foo.js",
"chars": 144,
"preview": "'use strict';\n\nmodule.exports = function(app) {\n class Foo extends app.Service {\n * get() {\n return 'bar';\n "
}
]
// ... and 83 more files (download for full content)
About this extraction
This page contains the full source code of the eggjs/egg-mock GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 283 files (291.6 KB), approximately 90.3k tokens, and a symbol index with 229 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.