[
  {
    "path": ".eslintrc",
    "content": "{\n  \"extends\": \"eslint-config-egg\",\n  \"globals\": {\n    \"beforeAll\": true\n  }\n}\n"
  },
  {
    "path": ".github/workflows/nodejs.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  Job:\n    name: Node.js\n    uses: node-modules/github-actions/.github/workflows/node-test.yml@master\n    with:\n      os: 'ubuntu-latest'\n      version: '14.18.0, 14, 16, 18, 20, 22'\n    secrets:\n      CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/pkg.pr.new.yml",
    "content": "name: Publish Any Commit\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - run: corepack enable\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 20\n\n      - name: Install dependencies\n        run: npm install\n\n      - name: Build\n        run: npm run prepublishOnly --if-present\n\n      - run: npx pkg-pr-new publish\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches: [ master ]\n\njobs:\n  release:\n    name: Node.js\n    uses: eggjs/github-actions/.github/workflows/node-release.yml@master\n    secrets:\n      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n      GIT_TOKEN: ${{ secrets.GIT_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules/\ncoverage/\nlogs/\n!test/fixtures/apps/app-not-clean/logs/keep\n!test/fixtures/yadan/node_modules\nrun/\n.vscode\n.idea\n.nyc_output\npackage-lock.json\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# 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* try to use urllib4 ([#177](https://github.com/eggjs/egg-mock/issues/177)) ([c8551b9](https://github.com/eggjs/egg-mock/commit/c8551b98f044c7315a67f579cc2c1b4f5dde73c4))\n\n## [5.15.0](https://github.com/eggjs/egg-mock/compare/v5.14.0...v5.15.0) (2024-12-10)\n\n\n### Features\n\n* use @eggjs/utils ([#176](https://github.com/eggjs/egg-mock/issues/176)) ([48000cb](https://github.com/eggjs/egg-mock/commit/48000cb468fd25ac258d728ecc9afca21a8f6284))\n\n## [5.14.0](https://github.com/eggjs/egg-mock/compare/v5.13.0...v5.14.0) (2024-12-09)\n\n\n### Features\n\n* 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))\n\n## [5.13.0](https://github.com/eggjs/egg-mock/compare/v5.12.5...v5.13.0) (2024-12-07)\n\n\n### Features\n\n* mv urllib to peerDependencies ([#174](https://github.com/eggjs/egg-mock/issues/174)) ([df7dc48](https://github.com/eggjs/egg-mock/commit/df7dc48be38f7f323f91213aa3ce3bd5e7879a58))\n\n## [5.12.5](https://github.com/eggjs/egg-mock/compare/v5.12.4...v5.12.5) (2024-07-05)\n\n\n### Bug Fixes\n\n* 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))\n\n## [5.12.4](https://github.com/eggjs/egg-mock/compare/v5.12.3...v5.12.4) (2024-07-04)\n\n\n### Bug Fixes\n\n* should reset agent on restore ([#171](https://github.com/eggjs/egg-mock/issues/171)) ([088ac41](https://github.com/eggjs/egg-mock/commit/088ac41d96daecf62c544ca954812d3721ac06cc))\n\n## [5.12.3](https://github.com/eggjs/egg-mock/compare/v5.12.2...v5.12.3) (2024-07-02)\n\n\n### Bug Fixes\n\n* don't close used mock agent ([#170](https://github.com/eggjs/egg-mock/issues/170)) ([3e7a504](https://github.com/eggjs/egg-mock/commit/3e7a5044e3a687c8accbfc9f8a60c469bf4fdad6))\n\n## [5.12.2](https://github.com/eggjs/egg-mock/compare/v5.12.1...v5.12.2) (2024-07-02)\n\n\n### Bug Fixes\n\n* export mockHttpClient types ([#169](https://github.com/eggjs/egg-mock/issues/169)) ([ddab25f](https://github.com/eggjs/egg-mock/commit/ddab25f1b06e1e513c2dd523bf7d773970d37031))\n\n## [5.12.1](https://github.com/eggjs/egg-mock/compare/v5.12.0...v5.12.1) (2024-07-02)\n\n\n### Bug Fixes\n\n* support httpclient mock on allowH2 = true ([#168](https://github.com/eggjs/egg-mock/issues/168)) ([3a434bb](https://github.com/eggjs/egg-mock/commit/3a434bb6a90c98b957b6d92e059c09297bf7cf18))\n\n## [5.12.0](https://github.com/eggjs/egg-mock/compare/v5.11.0...v5.12.0) (2024-06-02)\n\n\n### Features\n\n* 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))\n\n## [5.11.0](https://github.com/eggjs/egg-mock/compare/v5.10.9...v5.11.0) (2024-06-02)\n\n\n### Features\n\n* 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))\n\n## [5.10.9](https://github.com/eggjs/egg-mock/compare/v5.10.8...v5.10.9) (2023-11-08)\n\n\n### Bug Fixes\n\n* allow to call mockHttpclient multi times ([#165](https://github.com/eggjs/egg-mock/issues/165)) ([370e42d](https://github.com/eggjs/egg-mock/commit/370e42d777d89dcfde1773db6404284439b38725))\n\n## [5.10.8](https://github.com/eggjs/egg-mock/compare/v5.10.7...v5.10.8) (2023-06-21)\n\n\n### Bug Fixes\n\n* 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))\n\n## [5.10.7](https://github.com/eggjs/egg-mock/compare/v5.10.6...v5.10.7) (2023-05-29)\n\n\n### Bug Fixes\n\n* set types to index.d.ts ([#161](https://github.com/eggjs/egg-mock/issues/161)) ([7de47a1](https://github.com/eggjs/egg-mock/commit/7de47a1e6bb8d4d003b93c130d1e08c7ac0c8bf7))\n\n## [5.10.6](https://github.com/eggjs/egg-mock/compare/v5.10.5...v5.10.6) (2023-02-22)\n\n\n### Bug Fixes\n\n* disable app close on parallel ([#160](https://github.com/eggjs/egg-mock/issues/160)) ([5a08d33](https://github.com/eggjs/egg-mock/commit/5a08d33ffcbc047ef374a5ab99bee00ad5675808))\n\n## [5.10.5](https://github.com/eggjs/egg-mock/compare/v5.10.4...v5.10.5) (2023-02-16)\n\n\n### Bug Fixes\n\n* should close app on afterAll hook ([#158](https://github.com/eggjs/egg-mock/issues/158)) ([081b157](https://github.com/eggjs/egg-mock/commit/081b1574c31cfe274083b21a1e11bc81304ab1d5))\n\n## [5.10.4](https://github.com/eggjs/egg-mock/compare/v5.10.3...v5.10.4) (2023-01-31)\n\n\n### Bug Fixes\n\n* use symbol to access suite app ([#156](https://github.com/eggjs/egg-mock/issues/156)) ([a130dd3](https://github.com/eggjs/egg-mock/commit/a130dd307258df540b65b6d445b56681f69d9232))\n\n## [5.10.3](https://github.com/eggjs/egg-mock/compare/v5.10.2...v5.10.3) (2023-01-30)\n\n\n### Bug Fixes\n\n* 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))\n\n## [5.10.2](https://github.com/eggjs/egg-mock/compare/v5.10.1...v5.10.2) (2023-01-30)\n\n\n### Bug Fixes\n\n* 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))\n\n## [5.10.1](https://github.com/eggjs/egg-mock/compare/v5.10.0...v5.10.1) (2023-01-29)\n\n\n### Bug Fixes\n\n* fix mockContext with headers ([#153](https://github.com/eggjs/egg-mock/issues/153)) ([5e3e816](https://github.com/eggjs/egg-mock/commit/5e3e816395d8be37548d4bb72c3e3dc2d098bee1))\n\n## [5.10.0](https://github.com/eggjs/egg-mock/compare/v5.9.4...v5.10.0) (2023-01-28)\n\n\n### Features\n\n* add default ua egg-mock/${version} ([#151](https://github.com/eggjs/egg-mock/issues/151)) ([ccb28f5](https://github.com/eggjs/egg-mock/commit/ccb28f5a99148528459f1f8b120254f3feb64561))\n* impl setGetAppCallback ([#152](https://github.com/eggjs/egg-mock/issues/152)) ([b7d902c](https://github.com/eggjs/egg-mock/commit/b7d902cf990ee90181f24e9722f42560858118eb))\n\n## [5.9.4](https://github.com/eggjs/egg-mock/compare/v5.9.3...v5.9.4) (2023-01-18)\n\n\n### Bug Fixes\n\n* 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))\n\n## [5.9.3](https://github.com/eggjs/egg-mock/compare/v5.9.2...v5.9.3) (2023-01-18)\n\n\n### Bug Fixes\n\n* every it should has self ctx ([#150](https://github.com/eggjs/egg-mock/issues/150)) ([bf33c1c](https://github.com/eggjs/egg-mock/commit/bf33c1cbde00b0f10d49184bda305c2c98a58401))\n\n## [5.9.2](https://github.com/eggjs/egg-mock/compare/v5.9.1...v5.9.2) (2023-01-17)\n\n\n### Bug Fixes\n\n* mocha should be peer deps ([#148](https://github.com/eggjs/egg-mock/issues/148)) ([9a5fcca](https://github.com/eggjs/egg-mock/commit/9a5fcca1ff19f2bc7d74a8122becc1bf0ddfe89d))\n\n## [5.8.4](https://github.com/eggjs/egg-mock/compare/v5.8.3...v5.8.4) (2023-01-12)\n\n\n### Bug Fixes\n\n* 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))\n\n## [5.8.3](https://github.com/eggjs/egg-mock/compare/v5.8.2...v5.8.3) (2023-01-11)\n\n\n### Bug Fixes\n\n* 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))\n\n## [5.8.2](https://github.com/eggjs/egg-mock/compare/v5.8.1...v5.8.2) (2023-01-10)\n\n\n### Bug Fixes\n\n* 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))\n\n## [5.8.1](https://github.com/eggjs/egg-mock/compare/v5.8.0...v5.8.1) (2023-01-09)\n\n\n### Bug Fixes\n\n* add register.js to files ([#141](https://github.com/eggjs/egg-mock/issues/141)) ([a87e801](https://github.com/eggjs/egg-mock/commit/a87e8019724dbb2401bd41ccf95be26c571e8e8f))\n\n## [5.8.0](https://github.com/eggjs/egg-mock/compare/v5.7.1...v5.8.0) (2023-01-09)\n\n\n### Features\n\n* 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))\n\n## [5.7.1](https://github.com/eggjs/egg-mock/compare/v5.7.0...v5.7.1) (2023-01-07)\n\n\n### Bug Fixes\n\n* should add egg to peerDependencies ([#139](https://github.com/eggjs/egg-mock/issues/139)) ([2134fc7](https://github.com/eggjs/egg-mock/commit/2134fc73661e4c2de433aceda2ea45811c8bff8b))\n\n## [5.7.0](https://github.com/eggjs/egg-mock/compare/v5.6.0...v5.7.0) (2023-01-03)\n\n\n### Features\n\n* remove power-assert ([#138](https://github.com/eggjs/egg-mock/issues/138)) ([0c9fad2](https://github.com/eggjs/egg-mock/commit/0c9fad2f7a6f739080f2b996d8f6bb98852af12a))\n\n## [5.6.0](https://github.com/eggjs/egg-mock/compare/v5.5.0...v5.6.0) (2023-01-03)\n\n\n### Features\n\n* upgrade globby to v11 ([#137](https://github.com/eggjs/egg-mock/issues/137)) ([b0af3eb](https://github.com/eggjs/egg-mock/commit/b0af3eb471a394448236e4cb18863e60218e0d2a))\n\n## [5.5.0](https://github.com/eggjs/egg-mock/compare/v5.4.0...v5.5.0) (2022-12-28)\n\n\n### Features\n\n* add mockContextScope ([#136](https://github.com/eggjs/egg-mock/issues/136)) ([9db9afa](https://github.com/eggjs/egg-mock/commit/9db9afaadfb73a58d03b3cbdbd0c8c6515e6578a))\n\n---\n\n\n5.4.0 / 2022-12-14\n==================\n\n**features**\n  * [[`0bd71bc`](http://github.com/eggjs/egg-mock/commit/0bd71bc732b430f679854cceb5017238aca67f38)] - 📦 NEW: Allow restore mockAgent only (#134) (fengmk2 <<fengmk2@gmail.com>>)\n\n5.3.0 / 2022-12-09\n==================\n\n**features**\n  * [[`6608f01`](http://github.com/eggjs/egg-mock/commit/6608f01983b6891fad2eea758e426bb205dff117)] - 📦 NEW: mock context support ctxStorage (#133) (fengmk2 <<fengmk2@gmail.com>>)\n\n5.2.1 / 2022-11-11\n==================\n\n**fixes**\n  * [[`18c366d`](http://github.com/eggjs/egg-mock/commit/18c366d4d8f110e8b5e166bb4109be6659f59dd2)] - fix: use global hook for register global hook (#132) (killa <<killa123@126.com>>)\n\n5.2.0 / 2022-11-08\n==================\n\n**features**\n  * [[`209c921`](http://github.com/eggjs/egg-mock/commit/209c921cd07eeb541793d5eb28a4982c891ef337)] - feat: add EGG_FRAMEWORK for bootstrap custom framework (#131) (killa <<killa123@126.com>>)\n\n5.1.0 / 2022-11-04\n==================\n\n**features**\n  * [[`22f508c`](http://github.com/eggjs/egg-mock/commit/22f508cba2f6330172db89efde3a678ed35c5258)] - feat: impl parallel app for mocha parallel mode (#130) (killa <<killa123@126.com>>)\n\n5.0.2 / 2022-10-09\n==================\n\n**fixes**\n  * [[`299f7ec`](http://github.com/eggjs/egg-mock/commit/299f7ecc7314737c182c1745fce0d32c61cd657d)] - 🐛 FIX: Should use urllib-next package (#129) (fengmk2 <<fengmk2@gmail.com>>)\n\n**others**\n  * [[`17a6713`](http://github.com/eggjs/egg-mock/commit/17a6713663555f55832c12fa12c68803a59aa925)] - 🤖 TEST: Add httpclient streaming mocking (#128) (fengmk2 <<fengmk2@gmail.com>>)\n\n5.0.1 / 2022-09-29\n==================\n\n**features**\n  * [[`ae766ff`](http://github.com/eggjs/egg-mock/commit/ae766ff582a3e14a28b97e15bad5a56efcb542bc)] - 👌 IMPROVE: Mock httpclient support delay ms and repeat times (#127) (fengmk2 <<fengmk2@gmail.com>>)\n\n5.0.0 / 2022-09-29\n==================\n\n**features**\n  * [[`60658ec`](http://github.com/eggjs/egg-mock/commit/60658ecae4a16ac1e52dc3238c279a61262f4620)] - 📦 NEW: [BREAKING] Support egg 3.0 (#126) (fengmk2 <<fengmk2@gmail.com>>)\n\n4.2.1 / 2022-05-17\n==================\n\n**features**\n  * [[`983e610`](http://github.com/eggjs/egg-mock/commit/983e6106b3047f3c0b8d1871fecf4b851cb3000a)] - feat: allow other envtype (#125) (吖猩 <<whx89768@alibaba-inc.com>>)\n\n**others**\n  * [[`bb9cb79`](http://github.com/eggjs/egg-mock/commit/bb9cb79dbd3d8999cc887d1f0ea952b5df449086)] - 📖 DOC: Change ci status badge (fengmk2 <<fengmk2@gmail.com>>)\n  * [[`cd1f2db`](http://github.com/eggjs/egg-mock/commit/cd1f2dbd08683e60b31b83e3406c32a823124704)] - 📖 DOC: Update contributors (fengmk2 <<fengmk2@gmail.com>>)\n  * [[`74c0d8f`](http://github.com/eggjs/egg-mock/commit/74c0d8f5a9532fa9e3b3f1c29ad27b59d46ea984)] - Create codeql-analysis.yml (fengmk2 <<fengmk2@gmail.com>>)\n  * [[`6bcc866`](http://github.com/eggjs/egg-mock/commit/6bcc8660a94c761dbdcee0a09bcd6d06e8441f49)] - 🤖 TEST: Fix assert cases (#124) (fengmk2 <<fengmk2@gmail.com>>)\n\n4.2.0 / 2021-12-17\n==================\n\n**features**\n  * [[`b45ad40`](http://github.com/eggjs/egg-mock/commit/b45ad40dd572977986cd86220f090d28c1268b70)] - feat: add mockLog, expectLog to type define (#121) (fengmk2 <<fengmk2@gmail.com>>)\n\n4.1.0 / 2021-04-05\n==================\n\n**features**\n  * [[`ce6ecde`](https://github.com/eggjs/egg-mock.git/commit/ce6ecde700a81ce986347834dbd2dc2d48217f88)] - feat: add consoleLogger error when mockApp init error (mansonchor.github.com <<mansonchor1987@gmail.com>>)\n\n**others**\n  * [[`e7c73e3`](https://github.com/eggjs/egg-mock.git/commit/e7c73e37814b6c9041f37bbcd92b3bb7c35758b3)] - build: remove node@6 (dead-horse <<dead_horse@qq.com>>)\n\n4.0.1 / 2020-08-19\n==================\n\n**features**\n  * [[`d5e584e`](http://github.com/eggjs/egg-mock/commit/d5e584e769dd348bc87a99a90f0a6003dfc7a4cf)] - feat: httpclient support mock async function (#117) (Yiyu He <<dead_horse@qq.com>>)\n\n4.0.0 / 2020-03-01\n==================\n\n**features**\n  * [[`c39109f`](http://github.com/eggjs/egg-mock/commit/c39109faa0eff01d8597c3988c04459c3520f309)] - feat: upgrade mm@3 (#116) (Yiyu He <<dead_horse@qq.com>>)\n\n3.25.1 / 2020-01-17\n==================\n\n**fixes**\n  * [[`51ef091`](http://github.com/eggjs/egg-mock/commit/51ef091cbb06ae74ff7f9591e3071db648ba5346)] - fix: backgroundTasksFinished ensure all tasks finished (#115) (Yiyu He <<dead_horse@qq.com>>)\n\n3.25.0 / 2019-12-12\n==================\n\n**features**\n  * [[`4c31c9e`](http://github.com/eggjs/egg-mock/commit/4c31c9e2917eea449e2afddf96fc8d2aabe6ad5e)] - feat: support init hook before mock app init (#109) (TZ | 天猪 <<atian25@qq.com>>)\n\n**fixes**\n  * [[`cbab52a`](http://github.com/eggjs/egg-mock/commit/cbab52a697e6e47abd48ce45320b7c40a0463c12)] - fix: enable sendRandom() method in unittest (#114) (GoodMeowing <<36814673+GoodMeowing@users.noreply.github.com>>)\n\n3.24.2 / 2019-11-07\n==================\n\n**fixes**\n  * [[`3bf5ded`](http://github.com/eggjs/egg-mock/commit/3bf5ded501608f2b5b3199d8b3d0ca0329dd9df7)] - fix: mockLog don't read file (#113) (Yiyu He <<dead_horse@qq.com>>)\n\n3.24.1 / 2019-09-30\n==================\n\n**fixes**\n  * [[`bd305d2`](http://github.com/eggjs/egg-mock/commit/bd305d21bd54395e597f3fce06758fcbb99ba43f)] - fix: single mode will call app.agent.close (#108) (TZ | 天猪 <<atian25@qq.com>>)\n\n3.24.0 / 2019-09-26\n==================\n\n**features**\n  * [[`315e685`](http://github.com/eggjs/egg-mock/commit/315e685d2059ec61e62e9109da8b58f9bf5552cd)] - feat: support app.notExpectLog() (#107) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.23.2 / 2019-09-10\n==================\n\n**fixes**\n  * [[`e494325`](http://github.com/eggjs/egg-mock/commit/e494325562b84876a96062fd061ab4f8c7787a2e)] - fix: mockHttpclient with multi-request (#106) (吖猩 <<whx89768@alibaba-inc.com>>)\n  * [[`d836536`](http://github.com/eggjs/egg-mock/commit/d8365368e2339f25874a7dfc1c573249ae841e8f)] - fix: fix httpRequest function signature (#105) (Colin Cheng <<zbinlin@gmail.com>>)\n\n3.23.1 / 2019-05-20\n==================\n\n**fixes**\n  * [[`6be0c43`](http://github.com/eggjs/egg-mock/commit/6be0c431ee1fd651c4f0bb6f433d7c4444b74708)] - fix: rimraf (#104) (TZ | 天猪 <<atian25@qq.com>>)\n\n3.23.0 / 2019-05-20\n==================\n\n**features**\n  * [[`9ada7f0`](http://github.com/eggjs/egg-mock/commit/9ada7f004def359a0b17f3824cea946abe4ed1f2)] - feat: mockHttpclient support fn (#103) (TZ | 天猪 <<atian25@qq.com>>)\n\n3.22.4 / 2019-05-06\n==================\n\n**fixes**\n  * [[`478581a`](http://github.com/eggjs/egg-mock/commit/478581a7851d19286c4e689af421a70cae27d26d)] - fix: remove egg-core deps (#101) (TZ | 天猪 <<atian25@qq.com>>)\n\n3.22.3 / 2019-05-06\n==================\n\n**fixes**\n  * [[`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>>)\n\n3.22.2 / 2019-04-10\n==================\n\n**fixes**\n  * [[`a68ca65`](http://github.com/eggjs/egg-mock/commit/a68ca6549428e6c4dc886231d7c6b7fbefab46c6)] - fix: should emit server (#98) (TZ | 天猪 <<atian25@qq.com>>)\n\n3.22.1 / 2019-03-12\n==================\n\n**fixes**\n  * [[`3f73bad`](http://github.com/eggjs/egg-mock/commit/3f73bad59aa8acbb14399a914d31b8eb348ff493)] - fix: d.ts typo (#97) (TZ | 天猪 <<atian25@qq.com>>)\n\n3.22.0 / 2019-03-11\n==================\n\n**features**\n  * [[`81ed542`](http://github.com/eggjs/egg-mock/commit/81ed5427853067d84901c1848e630a8002ecfcf0)] - feat: add mock API for customLoader (#95) (Haoliang Gao <<sakura9515@gmail.com>>)\n\n**fixes**\n  * [[`58d0b32`](http://github.com/eggjs/egg-mock/commit/58d0b32a5851e4cd31492fe0e85c0e81336b6d04)] - fix:  remove nonexistent type and correct typing (#96) (Sinux <<askb@me.com>>)\n\n3.21.0 / 2018-12-27\n===================\n\n  **features**\n    * [[`93f8009`](https://github.com/eggjs/egg-mock/commit/93f8009c2f4c7d7f24b361f4713e035a2f993134)] - feat: cluster mock support result (#92) (TZ <<atian25@qq.com>>)\n    * [[`be3d146`](https://github.com/eggjs/egg-mock/commit/be3d1466bf438a379b85429c40c510d6be7ecc26)] - feat: bootstrap support run on jest env (#93) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.20.1 / 2018-09-17\n==================\n\n**fixes**\n  * [[`4b5dbb5`](http://github.com/eggjs/egg-mock/commit/4b5dbb512bf8f598d5ea5361c58ae9d40d528ff8)] - fix: add app.mockLog() to improve app.expectLog() more stable (#87) (fengmk2 <<fengmk2@gmail.com>>)\n\n**others**\n  * [[`a64db33`](http://github.com/eggjs/egg-mock/commit/a64db33d2ee68a76f7c41303e79e37099f33b373)] - deps: add egg-logger dependency (#88) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.20.0 / 2018-08-30\n==================\n\n**features**\n  * [[`283eef3`](http://github.com/eggjs/egg-mock/commit/283eef3a4f1b0bcd90cc0d6bcf6de9fe136d8503)] - feat: add `app.agent.mockHttpclient()` for agent (#82) (limerick <<guods2015@gmail.com>>)\n\n3.19.7 / 2018-08-28\n==================\n\n**fixes**\n  * [[`cc6b976`](http://github.com/eggjs/egg-mock/commit/cc6b976a66103dca44428e9ca4cf6e8d18b8323b)] - fix: app.messenger.broadcast send to self (君羽 <<ImHype@users.noreply.github.com>>)\n\n3.19.6 / 2018-08-24\n==================\n\n**fixes**\n  * [[`00fb82e`](http://github.com/eggjs/egg-mock/commit/00fb82eac8114f0be1a97421ea270947ea7b5efd)] - fix: fix declaration merging error (#86) (吖猩 <<whxaxes@qq.com>>)\n\n3.19.5 / 2018-08-24\n==================\n\n**fixes**\n  * [[`1635a90`](http://github.com/eggjs/egg-mock/commit/1635a9098d16df4ba4195d2e289476471bf96cb2)] - fix: show expectLog last 500 words on assert error (#85) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.19.4 / 2018-08-24\n===================\n\n  * feat: .d.ts 新增继承自 mm 的 api (#81)\n\n3.19.3 / 2018-08-16\n==================\n\n**fixes**\n  * [[`c91bf93`](http://github.com/eggjs/egg-mock/commit/c91bf93e792c788c4cdd7cf786a45fc2ecb4511d)] - fix: allow egg-core module missing (#83) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.19.2 / 2018-08-07\n==================\n\n**fixes**\n  * [[`1710f7f`](http://github.com/eggjs/egg-mock/commit/1710f7fcfdbd8709d6b4c50817ab0c214c525378)] - fix: put mock restore at the end (#80) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.19.1 / 2018-08-07\n==================\n\n**fixes**\n  * [[`db3cb11`](http://github.com/eggjs/egg-mock/commit/db3cb11a97ec6bdb3a70222a459241ffc3cc2c47)] - fix: make sure backgroundTasksFinished() return promise (#79) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.19.0 / 2018-08-06\n==================\n\n**features**\n  * [[`ab5a47e`](https://github.com/eggjs/egg-mock.git/commit/ab5a47e12f1fea4300a44ef19aa4ba300574d18a)] - feat: should wait for background task finish on afterEach (#78) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.18.0 / 2018-08-03\n==================\n\n**features**\n  * [[`f25c50a`](http://github.com/eggjs/egg-mock/commit/f25c50a24433e251e5c9f905170cea87e3ac93e6)] - feat: add `app.expectLog()` for app and cluster (#77) (fengmk2 <<fengmk2@gmail.com>>)\n\n**others**\n  * [[`ffb1187`](http://github.com/eggjs/egg-mock/commit/ffb1187aab11bc544c4bc6c5921ca0fba28e621f)] - chore: improve tsd and add bootstrap.d.ts (#76) (SuperEVO <<zhang740@qq.com>>)\n\n3.17.3 / 2018-07-14\n===================\n\n  * types: add bootstrap.d.ts (#75)\n\n3.17.2 / 2018-05-21\n==================\n\n**others**\n  * [[`62c3dfa`](http://github.com/eggjs/egg-mock/commit/62c3dfa517b94c56c35fed8af8d9aad29e7c38d4)] - refactor: middleware use promise-based style (#74) (Haoliang Gao <<sakura9515@gmail.com>>)\n\n3.17.1 / 2018-04-21\n===================\n\n  * fix: remove options.typescript support (#73)\n\n3.17.0 / 2018-03-30\n===================\n\n  * feat: support ts from env and pkg (#71)\n\n3.16.0 / 2018-03-28\n===================\n\n  * feat: support ts (#70)\n  * fix: mockSession save should not be enumerable (#69)\n\n3.15.1 / 2018-03-20\n==================\n\n**fixes**\n  * [[`3fbf862`](http://github.com/eggjs/egg-mock/commit/3fbf86232ee3c8e4944c8072e127c0f1ede1d26b)] - fix: mockSession save (#68) (TZ | 天猪 <<atian25@qq.com>>)\n\n3.15.0 / 2018-03-08\n==================\n\n**features**\n  * [[`9857065`](http://github.com/eggjs/egg-mock/commit/985706518e9ab8be155f285490484e5a304833fc)] - feat: add unexpectHeader() and expectHeader() (#67) (fengmk2 <<fengmk2@gmail.com>>)\n  * [[`f1820d7`](http://github.com/eggjs/egg-mock/commit/f1820d70f2e266d4b18fb7062976b4c14952a16f)] - feat: mm.app() support server event (#65) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.14.1 / 2018-02-28\n==================\n\n**fixes**\n  * [[`d38d615`](http://github.com/eggjs/egg-mock/commit/d38d615c3f9bc79eb09c6864ab9d5833a50d029a)] - fix: mockUrl accepts RegExp (#64) (Brick <<brick.c.yang@gmail.com>>)\n\n**others**\n  * [[`23c1075`](http://github.com/eggjs/egg-mock/commit/23c1075f5aaaa866b0243061d0eadf21ce67d382)] - test: add post with multipart file test cases (#63) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.14.0 / 2017-12-12\n==================\n\n**others**\n  * [[`be9bcd2`](http://github.com/eggjs/egg-mock/commit/be9bcd22c91044b0efdbc3db6b8109cf625002b1)] - refactor: modify d.ts and support bootstrap (Eward Song <<eward.song@gmail.com>>)\n\n3.13.1 / 2017-10-17\n==================\n\n**fixes**\n  * [[`9d071b2`](http://github.com/eggjs/egg-mock/commit/9d071b28c5ef341ee63ccb06f00f724922c698b2)] - fix: support mock the same property multiple times (#61) (Yiyu He <<dead_horse@qq.com>>)\n\n3.13.0 / 2017-10-10\n==================\n\n**features**\n  * [[`30ca0c9`](http://github.com/eggjs/egg-mock/commit/30ca0c980f3ee8b1f60f5213f0768fe5eeaaf49a)] - feat: port can be customized (#60) (Haoliang Gao <<sakura9515@gmail.com>>)\n\n3.12.2 / 2017-09-22\n==================\n\n**fixes**\n  * [[`5935564`](http://github.com/eggjs/egg-mock/commit/5935564d1e649f8702c0f3f79e67efde10717542)] - fix: missing methods package (dainli <<dainli@outlook.com>>)\n\n**others**\n  * [[`e7f518a`](http://github.com/eggjs/egg-mock/commit/e7f518a92e1686973bea557eb0a21f1d293ab0b4)] - fix(mockHttpclient): should use the copy of mockResult (#58) (Haoliang Gao <<sakura9515@gmail.com>>)\n * [new tag]         3.12.1     -> 3.12.1\n\n\n3.12.1 / 2017-09-13\n==================\n\n**others**\n  * [[`e7f518a`](http://github.com/eggjs/egg-mock/commit/e7f518a92e1686973bea557eb0a21f1d293ab0b4)] - fix(mockHttpclient): should use the copy of mockResult (#58) (Haoliang Gao <<sakura9515@gmail.com>>)\n\n3.12.0 / 2017-09-12\n==================\n\n**others**\n  * [[`25a0e28`](http://github.com/eggjs/egg-mock/commit/25a0e28e85209ec08a593b38cd434ed389ef8887)] - feat(mockHttpclient): use Regular Expression for matching url (#57) (Haoliang Gao <<sakura9515@gmail.com>>)\n\n3.11.0 / 2017-09-11\n==================\n\n**features**\n  * [[`f1a08a6`](http://github.com/eggjs/egg-mock/commit/f1a08a654a08313c0848828ee9051f8bf174fc6a)] - feat: support httpRequest().get(routerName) (#56) (fengmk2 <<fengmk2@gmail.com>>)\n\n3.10.0 / 2017-08-30\n==================\n\n**features**\n  * [[`f3654df`](http://github.com/eggjs/egg-mock/commit/f3654df99d4bee2ea0ee1ef580af7af66f21255d)] - feat: base promise to support async function (#55) (Yiyu He <<dead_horse@qq.com>>)\n\n3.9.1 / 2017-08-14\n==================\n\n**fixes**\n  * [[`d6cafaa`](http://github.com/eggjs/egg-mock/commit/d6cafaa531d9bbcc0fc987e7d6fdefd6a515e785)] - fix: fix agent type after ready (#54) (zōng yǔ <<gxcsoccer@users.noreply.github.com>>)\n\n3.9.0 / 2017-08-02\n==================\n\n**features**\n  * [[`9e1642c`](http://github.com/eggjs/egg-mock/commit/9e1642c7fc569d3cc4a73c9ede6511a18cca6fc5)] - feat: add bootstrap (#53) (Yiyu He <<dead-horse@users.noreply.github.com>>)\n\n3.8.0 / 2017-06-21\n==================\n\n  * deps: upgrade dependencies (#51)\n  * test: disable coverage when mm.cluster (#50)\n\n3.7.2 / 2017-06-07\n==================\n\n  * fix(httpclient): miss headers on options when emit response (#49)\n\n3.7.1 / 2017-06-01\n==================\n\n  * fix: detect prop object type can be non string (#48)\n\n3.7.0 / 2017-05-18\n===================\n\n  * feat: support prerequire files (#46)\n\n3.6.1 / 2017-05-11\n==================\n\n  * fix: ignore all error on cluster mock restore (#45)\n\n3.6.0 / 2017-05-10\n==================\n\n  * chore: add tsd (#43)\n  * feat: support mock function on cluster mode (#44)\n  * deps: upgrade dependencies (#42)\n\n3.5.0 / 2017-04-25\n==================\n\n  * feat: mockUrllib support async function (#41)\n\n3.4.0 / 2017-04-17\n==================\n\n  * feat: should pass when emit egg-ready (#39)\n\n3.3.0 / 2017-04-15\n==================\n\n  * feat: add app.httpRequest() test helper (#38)\n\n3.2.0 / 2017-03-14\n==================\n\n  * feat: mockHttpClient support mock multi methods (#35)\n  * test: remove userrole (#34)\n\n3.1.2 / 2017-03-05\n==================\n\n  * fix: should pass all arguments when mockCookies (#33)\n\n3.1.1 / 2017-03-04\n==================\n\n  * fix: egg-mock is not a framework (#32)\n\n3.1.0 / 2017-03-02\n==================\n\n  * feat: use framework instead of customEgg (#31)\n\n3.0.1 / 2017-02-22\n==================\n\n  * fix: app.close in right order (#30)\n\n3.0.0 / 2017-02-13\n==================\n\n  * deps: upgrade egg (#29)\n  * fix: bind messenger with app and agent (#28)\n  * feat: [BREAKING_CHANGE] can get error from .ready() (#27)\n  * test: remove unuse codes (#26)\n\n2.4.0 / 2017-02-08\n==================\n\n  * feat: listen error that thrown when app init (#25)\n\n2.3.1 / 2017-01-26\n==================\n\n  * fix: improve proxy handler and event listener (#24)\n\n2.3.0 / 2017-01-25\n==================\n\n  * feat: cluster-client support for mm.app (#23)\n\n2.2.0 / 2017-01-25\n==================\n\n  * feat: reimplement mm.app (#22)\n\n2.1.0 / 2017-01-16\n==================\n\n  * feat: support read framework from package.json (#20)\n\n2.0.0 / 2017-01-12\n==================\n\n  * refactor: use mockHttpclient instead of mockUrllib (#19)\n\n1.3.0 (deprecated) / 2017-01-12\n==================\n\n  * refactor: use mockHttpclient instead of mockUrllib (#19)\n\n1.2.1 / 2017-01-09\n==================\n\n  * fix: can't override data when mockContext(data) (#18)\n  * fix: replace the internal link into an github link in the env comment. (#17)\n\n1.2.0 / 2016-11-11\n==================\n\n  * feat: try to lookup egg that will be the default customEgg (#16)\n  * fix: don't use cache when app from cache is closed (#15)\n\n1.1.0 / 2016-11-02\n==================\n\n  * feat: add mm.home (#14)\n\n1.0.0 / 2016-11-01\n==================\n\n  * test: add testcase (#10)\n\n0.0.8 / 2016-10-25\n==================\n\n  * feat: wait 10ms to close app (#13)\n\n0.0.7 / 2016-10-25\n==================\n\n  * feat: should close agent when app close (#12)\n\n0.0.6 / 2016-10-24\n==================\n\n  * feat: cluster should wait process exit (#11)\n  * docs:update readme (#9)\n  * docs: update readme\n\n0.0.5 / 2016-10-11\n==================\n\n  * feat: pass opt to coffee (#7)\n\n0.0.4 / 2016-08-16\n==================\n\n  * fix: add eggPath for new egg (#5)\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017-present Alibaba Group Holding Limited and other contributors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# egg-mock\n\n[![NPM version][npm-image]][npm-url]\n[![Node.js CI](https://github.com/eggjs/egg-mock/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eggjs/egg-mock/actions/workflows/nodejs.yml)\n[![Test coverage][codecov-image]][codecov-url]\n[![npm download][download-image]][download-url]\n\n[npm-image]: https://img.shields.io/npm/v/egg-mock.svg?style=flat-square\n[npm-url]: https://npmjs.org/package/egg-mock\n[codecov-image]: https://codecov.io/github/eggjs/egg-mock/coverage.svg?branch=master\n[codecov-url]: https://codecov.io/github/eggjs/egg-mock?branch=master\n[download-image]: https://img.shields.io/npm/dm/egg-mock.svg?style=flat-square\n[download-url]: https://npmjs.org/package/egg-mock\n\nMock 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.\n\n## Install\n\n```bash\n$ npm i egg-mock --save-dev\n```\n\n## Usage\n\n### Create testcase\n\nLaunch a mock server with `mm.app`\n\n```js\n// test/index.test.js\nconst path = require('path');\nconst mm = require('egg-mock');\n\ndescribe('some test', () => {\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: 'apps/foo'\n    });\n    return app.ready();\n  })\n  after(() => app.close());\n\n  it('should request /', () => {\n    return app.httpRequest()\n      .get('/')\n      .expect(200);\n  });\n});\n```\n\nRetrieve Agent instance through `app.agent` after `mm.app` started.\n\nUsing `mm.cluster` launch cluster server, you can use the same API as `mm.app`;\n\n### Test Application\n\n`baseDir` is optional that is `process.cwd()` by default.\n\n```js\nbefore(() => {\n  app = mm.app();\n  return app.ready();\n});\n```\n\n### Test Framework\n\nframework is optional, it's `node_modules/egg` by default.\n\n```js\nbefore(() => {\n  app = mm.app({\n    baseDir: 'apps/demo',\n    framework: true,\n  });\n  return app.ready();\n});\n```\n\n### Test Plugin\n\nIf `eggPlugin.name` is defined in `package.json`, it's a plugin that will be loaded to plugin list automatically.\n\n```js\nbefore(() => {\n  app = mm.app({\n    baseDir: 'apps/demo',\n  });\n  return app.ready();\n});\n```\n\nYou 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.\n\n```js\ndescribe('aliyun-egg', () => {\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: 'apps/demo',\n      framework: path.join(__dirname, 'node_modules/aliyun-egg'),\n    });\n    return app.ready();\n  });\n});\n\ndescribe('framework-b', () => {\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: 'apps/demo',\n      framework: path.join(__dirname, 'node_modules/framework-b'),\n    });\n    return app.ready();\n  });\n});\n```\n\nIf it's detected as an plugin, but you don't want it to be, you can use `plugin = false`.\n\n```js\nbefore(() => {\n  app = mm.app({\n    baseDir: 'apps/demo',\n    plugin: false,\n  });\n  return app.ready();\n});\n```\n\n## API\n\n### mm.app(options)\n\nCreate a mock application.\n\n### mm.cluster(options)\n\nCreate a mock cluster server, but you can't use API in application, you should test using `supertest`.\n\n```js\nconst mm = require('egg-mock');\ndescribe('test/app.js', () => {\n  let app, config;\n  before(() => {\n    app = mm.cluster();\n    return app.ready();\n  });\n  after(() => app.close());\n\n  it('some test', () => {\n    return app.httpRequest()\n      .get('/config')\n      .expect(200)\n  });\n});\n```\n\nYou can disable coverage, because it's slow.\n\n```js\nmm.cluster({\n  coverage: false,\n});\n```\n\n### mm.env(env)\n\nMock env when starting\n\n```js\n// production environment\nmm.env('prod');\nmm.app({\n  cache: false,\n});\n```\n\nEnvironment list <https://github.com/eggjs/egg-core/blob/master/lib/loader/egg_loader.js#L82>\n\n### mm.consoleLevel(level)\n\nMock level that print to stdout/stderr\n\n```js\n// DON'T log to terminal\nmm.consoleLevel('NONE');\n```\n\nlevel list: `DEBUG`, `INFO`, `WARN`, `ERROR`, `NONE`\n\n### mm.home(homePath)\n\nmock home directory\n\n### mm.restore()\n\nrestore all mock data, e.g. `afterEach(mm.restore)`\n\n### options\n\nOptions for `mm.app` and `mm.cluster`\n\n#### baseDir {String}\n\nThe directory of application, default is `process.cwd()`.\n\n```js\nmm.app({\n  baseDir: path.join(__dirname, 'fixtures/apps/demo'),\n})\n```\n\nYou can use a string based on `$CWD/test/fixtures` for short\n\n```js\nmm.app({\n  baseDir: 'apps/demo',\n})\n```\n\n#### framework {String/Boolean}\n\nThe directory of framework\n\n```js\nmm.app({\n  baseDir: 'apps/demo',\n  framework: path.join(__dirname, 'fixtures/egg'),\n})\n```\n\nIt can be true when test an framework\n\n#### plugin\n\nThe directory of plugin, it's detected automatically.\n\n```js\nmm.app({\n  baseDir: 'apps/demo',\n})\n```\n\n#### plugins {Object}\n\nDefine a list of plugins\n\n#### cache {Boolean}\n\nDetermine whether enable cache. it's cached by baseDir.\n\n#### clean {Boolean}\n\nClean all logs directory, default is true.\n\nIf you are using `ava`, disable it.\n\n### app.mockLog([logger]) and app.expectLog(str[, logger]), app.notExpectLog(str[, logger])\n\nAssert some string value in the logger instance.\nIt is recommended to pair `app.mockLog()` with `app.expectLog()` or `app.notExpectLog()`.\nUsing `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.\n\n```js\nit('should work', async () => {\n  app.mockLog();\n  await app.httpRequest()\n    .get('/')\n    .expect('hello world')\n    .expect(200);\n\n  app.expectLog('foo in logger');\n  app.expectLog('foo in coreLogger', 'coreLogger');\n  app.expectLog('foo in myCustomLogger', 'myCustomLogger');\n\n  app.notExpectLog('bar in logger');\n  app.notExpectLog('bar in coreLogger', 'coreLogger');\n  app.notExpectLog('bar in myCustomLogger', 'myCustomLogger');\n});\n```\n\n### app.httpRequest()\n\nRequest current app http server.\n\n```js\nit('should work', () => {\n  return app.httpRequest()\n    .get('/')\n    .expect('hello world')\n    .expect(200);\n});\n```\n\nSee [supertest](https://github.com/visionmedia/supertest) to get more APIs.\n\n#### .unexpectHeader(name)\n\nAssert current response not contains the specified header\n\n```js\nit('should work', () => {\n  return app.httpRequest()\n    .get('/')\n    .unexpectHeader('set-cookie')\n    .expect(200);\n});\n```\n\n#### .expectHeader(name)\n\nAssert current response contains the specified header\n\n```js\nit('should work', () => {\n  return app.httpRequest()\n    .get('/')\n    .expectHeader('set-cookie')\n    .expect(200);\n});\n```\n\n### app.mockContext(options)\n\n```js\nconst ctx = app.mockContext({\n  user: {\n    name: 'Jason'\n  }\n});\nconsole.log(ctx.user.name); // Jason\n```\n\n### app.mockContextScope(fn, options)\n\n```js\nawait app.mockContextScope(async ctx => {\n  console.log(ctx.user.name); // Jason\n}, {\n  user: {\n    name: 'Jason'\n  }\n});\n```\n\n### app.mockCookies(data)\n\n```js\napp.mockCookies({\n  foo: 'bar'\n});\nconst ctx = app.mockContext();\nconsole.log(ctx.getCookie('foo'));\n```\n\n### app.mockHeaders(data)\n\nMock request header\n\n### app.mockSession(data)\n\n```js\napp.mockSession({\n  foo: 'bar'\n});\nconst ctx = app.mockContext();\nconsole.log(ctx.session.foo);\n```\n\n### app.mockService(service, methodName, fn)\n\n```js\nit('should mock user name', function* () {\n  app.mockService('user', 'getName', function* (ctx, methodName, args) {\n    return 'popomore';\n  });\n  const ctx = app.mockContext();\n  yield ctx.service.user.getName();\n});\n```\n\n### app.mockServiceError(service, methodName, error)\n\nYou can mock an error for service\n\n```js\napp.mockServiceError('user', 'home', new Error('mock error'));\n```\n\n### app.mockCsrf()\n\n```js\napp.mockCsrf();\n\nreturn app.httpRequest()\n  .post('/login')\n  .expect(302);\n```\n\n### app.mockHttpclient(url, method, data)\n\nMock httpclient request, e.g.: `ctx.curl`\n\n```js\napp.get('/', function*() {\n  const ret = yield this.curl('https://eggjs.org');\n  this.body = ret.data.toString();\n});\n\napp.mockHttpclient('https://eggjs.org', {\n  // can be buffer / string / json / function\n  // will auto convert to buffer\n  // follow options.dataType to convert\n  data: 'mock egg',\n});\n// app.mockHttpclient('https://eggjs.org', 'get', mockResponse); // mock get\n// app.mockHttpclient('https://eggjs.org', [ 'get' , 'head' ], mockResponse); // mock get and head\n// app.mockHttpclient('https://eggjs.org', '*', mockResponse); // mock all methods\n// app.mockHttpclient('https://eggjs.org', mockResponse); // mock all methods by default\n// app.mockHttpclient('https://eggjs.org', 'get', function(url, opt) { return 'xxx' }); // support fn\n\nreturn app.httpRequest()\n  .post('/')\n  .expect('mock egg');\n```\n\nYou can also use Regular Expression for matching url.\n\n```js\napp.mockHttpclient(/\\/users\\/[a-z]$/i, {\n  data: {\n    name: 'egg',\n  },\n});\n```\n\nYou can alse mock agent.httpclient\n\n```js\napp.agent.mockHttpclient('https://eggjs.org', {\n  data: {\n    name: 'egg',\n  },\n});\n```\n\n## Bootstrap\n\nWe also provide a bootstrap file for applications' unit test to reduce duplicated code:\n\n```js\nconst { app, mock, assert } = require('egg-mock/bootstrap');\n\ndescribe('test app', () => {\n  it('should request success', () => {\n    // mock data will be restored each case\n    mock.data(app, 'method', { foo: 'bar' });\n    return app.httpRequest()\n      .get('/foo')\n      .expect(res => {\n        assert(!res.headers.foo);\n      })\n      .expect(/bar/);\n  });\n});\n\ndescribe('test ctx', () => {\n  it('can use ctx', async function() {\n    const res = await this.ctx.service.foo();\n    assert(res === 'foo');\n  });\n});\n```\n\nWe inject ctx to every test case, so you can use `app.currentContext` in your test case.\nand the first call of `app.mockContext` will reuse `app.currentContext`.\n\n```js\nconst { app, mock, assert } = require('egg-mock/bootstrap');\n\ndescribe('test ctx', () => {\n  it('should can use ctx', () => {\n    const ctx = app.currentContext;\n    assert(ctx);\n  });\n\n  it('should reuse ctx', () => {\n    const ctx = app.currentContext;\n    // first call will reuse app.currentContext\n    const mockCtx = app.mockContext();\n    assert(ctx === mockCtx);\n    // next call will create a new context\n    // multi call app.mockContext will get wrong context with app.currentContext\n    // so we recommend to use app.mockContextScope\n    const mockCtx2 = app.mockContext();\n    assert(ctx !== mockCtx);\n  });\n});\n```\n\nAnd if you use mm.app to bootstrap app, you can manually call setGetAppCallback,\nthen egg-mock will inject ctx for each test case.\n```js\n// test/.setup.js\nconst mm = require('egg-mock');\nconst path = require('path');\nbefore(async function() {\n  const app = this.app = mm.app();\n  mm.setGetAppCallback(() => {\n    return app;\n  });\n  await app.ready();\n});\n\n\n// test/index.test.js\nit('should work', function() {\n  // eslint-disable-next-line no-undef\n  assert(this.app.currentContext);\n});\n```\n\n### env for custom bootstrap\n\nEGG_BASE_DIR: the base dir of egg app\nEGG_FRAMEWORK: the framework of egg app\n\n## Questions & Suggestions\n\nPlease open an issue [here](https://github.com/eggjs/egg/issues).\n\n## License\n\n[MIT](LICENSE)\n\n## Contributors\n\n[![Contributors](https://contrib.rocks/image?repo=eggjs/egg-mock)](https://github.com/eggjs/egg-mock/graphs/contributors)\n\nMade with [contributors-img](https://contrib.rocks).\n"
  },
  {
    "path": "README.zh_CN.md",
    "content": "# egg-mock\n\n[![NPM version][npm-image]][npm-url]\n[![Node.js CI](https://github.com/eggjs/egg-mock/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eggjs/egg-mock/actions/workflows/nodejs.yml)\n[![Test coverage][codecov-image]][codecov-url]\n[![npm download][download-image]][download-url]\n\n[npm-image]: https://img.shields.io/npm/v/egg-mock.svg?style=flat-square\n[npm-url]: https://npmjs.org/package/egg-mock\n[codecov-image]: https://codecov.io/github/eggjs/egg-mock/coverage.svg?branch=master\n[codecov-url]: https://codecov.io/github/eggjs/egg-mock?branch=master\n[download-image]: https://img.shields.io/npm/dm/egg-mock.svg?style=flat-square\n[download-url]: https://npmjs.org/package/egg-mock\n\n一个数据模拟的库，更方便地测试 Egg 应用、插件及自定义 Egg 框架。`egg-mock` 拓展自 [node_modules/mm](https://github.com/node-modules/mm)，你可以使用所有 `mm` 包含的 API。\n\n## Install\n\n```bash\n$ npm i egg-mock --save-dev\n```\n\n## Usage\n\n### 创建测试用例\n\n通过 `mm.app` 启动应用，可以使用 App 的 API 模拟数据\n\n```js\n// test/index.test.js\nconst path = require('path');\nconst mm = require('egg-mock');\n\ndescribe('some test', () => {\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: 'apps/foo'\n      customEgg: path.join(__dirname, '../node_modules/egg'),\n    });\n    return app.ready();\n  })\n  after(() => app.close());\n\n  it('should request /', () => {\n    return app.httpRequest()\n      .get('/')\n      .expect(200);\n  });\n});\n```\n\n使用 `mm.app` 启动后可以通过 `app.agent` 访问到 agent 对象。\n\n使用 `mm.cluster` 启动多进程测试，API 与 `mm.app` 一致。\n\n### 应用开发者\n\n应用开发者不需要传入 baseDir，其为当前路径\n\n```js\nbefore(() => {\n  app = mm.app({\n    customEgg: path.join(__dirname, '../node_modules/egg'),\n  });\n  return app.ready();\n});\n```\n\n### 框架开发者\n\n框架开发者需要指定 customEgg，会将当前路径指定为框架入口\n\n```js\nbefore(() => {\n  app = mm.app({\n    baseDir: 'apps/demo',\n    customEgg: true,\n  });\n  return app.ready();\n});\n```\n\n### 插件开发者\n\n在插件目录下执行测试用例时，只要 `package.json` 中有 `eggPlugin.name` 字段，就会自动把当前目录加到插件列表中。\n\n```js\nbefore(() => {\n  app = mm.app({\n    baseDir: 'apps/demo',\n    customEgg: path.join(__dirname, '../node_modules/egg'),\n  });\n  return app.ready();\n});\n```\n\n也可以通过 customEgg 指定其他框架，比如希望在 aliyun-egg 和 framework-b 同时测试此插件。\n\n```js\ndescribe('aliyun-egg', () => {\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: 'apps/demo',\n      customEgg: path.join(__dirname, 'node_modules/aliyun-egg'),\n    });\n    return app.ready();\n  });\n});\n\ndescribe('framework-b', () => {\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: 'apps/demo',\n      customEgg: path.join(__dirname, 'node_modules/framework-b'),\n    });\n    return app.ready();\n  });\n});\n```\n\n如果当前目录确实是一个 egg 插件，但是又不想当它是一个插件来测试，可以通过 `options.plugin` 选项来关闭：\n\n```js\nbefore(() => {\n  app = mm.app({\n    baseDir: 'apps/demo',\n    customEgg: path.join(__dirname, 'node_modules/egg'),\n    plugin: false,\n  });\n  return app.ready();\n});\n```\n\n## API\n\n### mm.app(options)\n\n创建一个 mock 的应用。\n\n### mm.cluster(options)\n\n创建一个多进程应用，因为是多进程应用，无法获取 worker 的属性，只能通过 supertest 请求。\n\n```js\nconst mm = require('egg-mock');\ndescribe('test/app.js', () => {\n  let app, config;\n  before(() => {\n    app = mm.cluster();\n    return app.ready();\n  });\n  after(() => app.close());\n\n  it('some test', () => {\n    return app.httpRequest()\n      .get('/config')\n      .expect(200)\n  });\n});\n```\n\n默认会启用覆盖率，因为覆盖率比较慢，可以设置 coverage 关闭\n\n```js\nmm.cluster({\n  coverage: false,\n});\n```\n\n### mm.env(env)\n\n设置环境变量，主要用于启动阶段，运行阶段可以使用 app.mockEnv。\n\n```js\n// 模拟生成环境\nmm.env('prod');\nmm.app({\n  cache: false,\n});\n```\n\n具体值见 <https://github.com/eggjs/egg-core/blob/master/lib/loader/egg_loader.js#L82>\n\n### mm.consoleLevel(level)\n\nmock 终端日志打印级别\n\n```js\n// 不输出到终端\nmm.consoleLevel('NONE');\n```\n\n可选 level 为 `DEBUG`, `INFO`, `WARN`, `ERROR`, `NONE`\n\n### mm.home(homePath)\n\n模拟操作系统用户目录\n\n### mm.restore\n\n还原所有 mock 数据，一般需要结合 `afterEach(mm.restore)` 使用\n\n### options\n\nmm.app 和 mm.cluster 的配置参数\n\n#### baseDir {String}\n\n当前应用的目录，如果是应用本身的测试可以不填默认为 $CWD。\n\n指定完整路径\n\n```js\nmm.app({\n  baseDir: path.join(__dirname, 'fixtures/apps/demo'),\n})\n```\n\n也支持缩写，找 test/fixtures 目录下的\n\n```js\nmm.app({\n  baseDir: 'apps/demo',\n})\n```\n\n#### customEgg {String/Boolean}\n\n指定框架路径\n\n```js\nmm.app({\n  baseDir: 'apps/demo',\n  customEgg: path.join(__dirname, 'fixtures/egg'),\n})\n```\n\n对于框架的测试用例，可以指定 true，会自动加载当前路径。\n\n#### plugin\n\n指定插件的路径，只用于插件测试。设置为 true 会将当前路径设置到插件列表。\n\n```js\nmm.app({\n  baseDir: 'apps/demo',\n  plugin: true,\n})\n```\n\n#### plugins {Object}\n\n传入插件列表，可以自定义多个插件\n\n#### cache {Boolean}\n\n是否需要缓存，默认开启。\n\n是通过 baseDir 缓存的，如果不需要可以关闭，但速度会慢。\n\n#### clean {Boolean}\n\n是否需要清理 log 目录，默认开启。\n\n如果是通过 ava 等并行测试框架进行测试，需要手动在执行测试前进行统一的日志清理，不能通过 mm 来处理，设置 `clean` 为 `false`。\n\n### app.mockLog([logger]) and app.expectLog(str[, logger]), app.notExpectLog(str[, logger])\n\n断言指定的字符串记录在指定的日志中。\n建议 `app.mockLog()` 和 `app.expectLog()` 或者 `app.notExpectLog()` 配对使用。\n单独使用 `app.expectLog()` 或者 `app.notExpectLog()` 需要依赖日志的写入速度，在服务器磁盘高 IO 的时候，会出现不稳定的结果。\n\n```js\nit('should work', async () => {\n  // 将日志记录到内存，用于下面的 expectLog\n  app.mockLog();\n  await app.httpRequest()\n    .get('/')\n    .expect('hello world')\n    .expect(200);\n\n  app.expectLog('foo in logger');\n  app.expectLog('foo in coreLogger', 'coreLogger');\n  app.expectLog('foo in myCustomLogger', 'myCustomLogger');\n\n  app.notExpectLog('bar in logger');\n  app.notExpectLog('bar in coreLogger', 'coreLogger');\n  app.notExpectLog('bar in myCustomLogger', 'myCustomLogger');\n});\n```\n\n### app.httpRequest()\n\n请求当前应用 http 服务的辅助工具。\n\n```js\nit('should work', () => {\n  return app.httpRequest()\n    .get('/')\n    .expect('hello world')\n    .expect(200);\n});\n```\n\n更多信息请查看 [supertest](https://github.com/visionmedia/supertest) 的 API 说明。\n\n#### .unexpectHeader(name)\n\n断言当前请求响应不包含指定 header\n\n```js\nit('should work', () => {\n  return app.httpRequest()\n    .get('/')\n    .unexpectHeader('set-cookie')\n    .expect(200);\n});\n```\n\n#### .expectHeader(name)\n\n断言当前请求响应包含指定 header\n\n```js\nit('should work', () => {\n  return app.httpRequest()\n    .get('/')\n    .expectHeader('set-cookie')\n    .expect(200);\n});\n```\n\n### app.mockContext(options)\n\n模拟上下文数据\n\n```js\nconst ctx = app.mockContext({\n  user: {\n    name: 'Jason'\n  }\n});\nconsole.log(ctx.user.name); // Jason\n```\n\n### app.mockContextScope(fn, options)\n\n安全的模拟上下文数据，同一用例用多次调用 mockContext 可能会造成 AsyncLocalStorage 污染\n\n```js\nawait app.mockContextScope(async ctx => {\n  console.log(ctx.user.name); // Jason\n}, {\n  user: {\n    name: 'Jason'\n  }\n});\n```\n\n### app.mockCookies(data)\n\n```js\napp.mockCookies({\n  foo: 'bar'\n});\nconst ctx = app.mockContext();\nconsole.log(ctx.getCookie('foo'));\n```\n\n### app.mockHeaders(data)\n\n模拟请求头\n\n### app.mockSession(data)\n\n```js\napp.mockSession({\n  foo: 'bar'\n});\nconst ctx = app.mockContext();\nconsole.log(ctx.session.foo);\n```\n\n### app.mockService(service, methodName, fn)\n\n```js\nit('should mock user name', function* () {\n  app.mockService('user', 'getName', function* (ctx, methodName, args) {\n    return 'popomore';\n  });\n  const ctx = app.mockContext();\n  yield ctx.service.user.getName();\n});\n```\n\n### app.mockServiceError(service, methodName, error)\n\n可以模拟一个错误\n\n```js\napp.mockServiceError('user', 'home', new Error('mock error'));\n```\n\n### app.mockCsrf()\n\n模拟 csrf，不用传递 token\n\n```js\napp.mockCsrf();\n\nreturn app.httpRequest()\n  .post('/login')\n  .expect(302);\n```\n\n### app.mockHttpclient(url, method, data)\n\n模拟 httpclient 的请求，例如 `ctx.curl`\n\n```js\napp.get('/', async ctx => {\n  const ret = await ctx.curl('https://eggjs.org');\n  this.body = ret.data.toString();\n});\n\napp.mockHttpclient('https://eggjs.org', {\n  // 模拟的参数，可以是 buffer / string / json / function\n  // 都会转换成 buffer\n  // 按照请求时的 options.dataType \b来做对应的转换\n  data: 'mock egg',\n});\n\nreturn app.httpRequest()\n  .post('/')\n  .expect('mock egg');\n```\n\n## Bootstrap\n\n我们提供了一个 bootstrap 来减少单测中的重复代码:\n\n```js\nconst { app, mock, assert } = require('egg-mock/bootstrap');\n\ndescribe('test app', () => {\n  it('should request success', () => {\n    // mock data will be restored each case\n    mock.data(app, 'method', { foo: 'bar' });\n    return app.httpRequest()\n      .get('/foo')\n      .expect(res => {\n        assert(!res.headers.foo);\n      })\n      .expect(/bar/);\n  });\n});\n\ndescribe('test ctx', () => {\n  it('can use ctx', async function() {\n    const res = await this.ctx.service.foo();\n    assert(res === 'foo');\n  });\n});\n```\n\n我们将会在每个 case 中自定注入 ctx, 可以通过 `app.currentContext` 来获取当前的 ctx。\n并且第一次使用 `app.mockContext` 会自动复用当前 case 的上下文。\n\n```js\nconst { app, mock, assert } = require('egg-mock/bootstrap');\n\ndescribe('test ctx', () => {\n  it('should can use ctx', () => {\n    const ctx = app.currentContext;\n    assert(ctx);\n  });\n\n  it('should reuse ctx', () => {\n    const ctx = app.currentContext;\n    // 第一次调用会复用上下文\n    const mockCtx = app.mockContext();\n    assert(ctx === mockCtx);\n    // 后续调用会新建上下文\n    // 极不建议多次调用 app.mockContext\n    // 这会导致上下文污染\n    // 建议使用 app.mockContextScope\n    const mockCtx2 = app.mockContext();\n    assert(ctx !== mockCtx);\n  });\n});\n```\n\n### env for custom bootstrap\n\nEGG_BASE_DIR: the base dir of egg app\nEGG_FRAMEWORK: the framework of egg app\n\n## Questions & Suggestions\n\nPlease open an issue [here](https://github.com/eggjs/egg/issues).\n\n## License\n\n[MIT](LICENSE)\n\n## Contributors\n\n[![Contributors](https://contrib.rocks/image?repo=eggjs/egg-mock)](https://github.com/eggjs/egg-mock/graphs/contributors)\n\nMade with [contributors-img](https://contrib.rocks).\n"
  },
  {
    "path": "app/extend/agent.js",
    "content": "const mm = require('mm');\nconst mockHttpclient = require('../../lib/mock_httpclient');\nconst mockAgent = require('../../lib/mock_agent');\n\nmodule.exports = {\n  /**\n   * mock httpclient\n   * @function Agent#mockHttpclient\n   * @param {...any} args - args\n   * @return {Context} this\n   */\n  mockHttpclient(...args) {\n    if (!this._mockHttpclient) {\n      this._mockHttpclient = mockHttpclient(this);\n    }\n    return this._mockHttpclient(...args);\n  },\n\n  /**\n   * get mock httpclient agent\n   * @function Agent#mockHttpclientAgent\n   * @return {MockAgent} agent\n   */\n  mockAgent() {\n    return mockAgent.getAgent(this);\n  },\n\n  async mockAgentRestore() {\n    await mockAgent.restore();\n  },\n\n  /**\n   * @see mm#restore\n   * @function Agent#mockRestore\n   */\n  mockRestore: mm.restore,\n\n  /**\n   * @see mm\n   * @function Agent#mm\n   */\n  mm,\n};\n"
  },
  {
    "path": "app/extend/application.js",
    "content": "const debug = require('util').debuglog('egg-mock:application');\nconst mm = require('mm');\nconst http = require('http');\nconst fs = require('fs');\nconst merge = require('merge-descriptors');\nconst is = require('is-type-of');\nconst assert = require('assert');\nconst Transport = require('egg-logger').Transport;\nconst mockAgent = require('../../lib/mock_agent');\nconst mockHttpclient = require('../../lib/mock_httpclient');\nconst supertestRequest = require('../../lib/supertest');\n\nconst ORIGIN_TYPES = Symbol('egg-mock:originTypes');\nconst BACKGROUND_TASKS = Symbol('Application#backgroundTasks');\nconst REUSED_CTX = Symbol('Context#reusedInSuite');\n\nmodule.exports = {\n  /**\n   * mock Context\n   * @function App#mockContext\n   * @param {Object} data - ctx data\n   * @param {Object} [options] - mock ctx options\n   * @return {Context} ctx\n   * @example\n   * ```js\n   * const ctx = app.mockContext({\n   *   user: {\n   *     name: 'Jason'\n   *   }\n   * });\n   * console.log(ctx.user.name); // Jason\n   *\n   * // controller\n   * module.exports = function*() {\n   *   this.body = this.user.name;\n   * };\n   * ```\n   */\n  mockContext(data, options) {\n    function mockRequest(req) {\n      for (const key in (data.headers) || {}) {\n        mm(req.headers, key, data.headers[key]);\n        mm(req.headers, key.toLowerCase(), data.headers[key]);\n      }\n    }\n\n    options = Object.assign({ mockCtxStorage: true }, options);\n    data = data || {};\n\n    if (this._customMockContext) {\n      this._customMockContext(data);\n    }\n\n    // 使用者自定义mock，可以覆盖上面的 mock\n    for (const key in data) {\n      mm(this.context, key, data[key]);\n    }\n\n    const req = this.mockRequest(data);\n    const res = new http.ServerResponse(req);\n\n    if (options.reuseCtxStorage !== false) {\n      if (this.currentContext && !this.currentContext[REUSED_CTX]) {\n        mockRequest(this.currentContext.request.req);\n        this.currentContext[REUSED_CTX] = true;\n        return this.currentContext;\n      }\n    }\n    const ctx = this.createContext(req, res);\n    if (options.mockCtxStorage) {\n      mm(this.ctxStorage, 'getStore', () => ctx);\n    }\n    return ctx;\n  },\n\n  async mockContextScope(fn, data) {\n    const ctx = this.mockContext(data, {\n      mockCtxStorage: false,\n      reuseCtxStorage: false,\n    });\n    return await this.ctxStorage.run(ctx, fn, ctx);\n  },\n\n  /**\n   * mock cookie session\n   * @function App#mockSession\n   * @param {Object} data - session object\n   * @return {App} this\n   */\n  mockSession(data) {\n    if (!data) {\n      return this;\n    }\n\n    if (is.object(data) && !data.save) {\n      Object.defineProperty(data, 'save', {\n        value: () => {},\n        enumerable: false,\n      });\n    }\n    mm(this.context, 'session', data);\n    return this;\n  },\n\n  /**\n   * Mock service\n   * @function App#mockService\n   * @param {String} service - name\n   * @param {String} methodName - method\n   * @param {Object/Function/Error} fn - mock you data\n   * @return {App} this\n   */\n  mockService(service, methodName, fn) {\n    if (typeof service === 'string') {\n      const arr = service.split('.');\n      service = this.serviceClasses;\n      for (const key of arr) {\n        service = service[key];\n      }\n      service = service.prototype || service;\n    }\n    this._mockFn(service, methodName, fn);\n    return this;\n  },\n\n  /**\n   * mock service that return error\n   * @function App#mockServiceError\n   * @param {String} service - name\n   * @param {String} methodName - method\n   * @param {Error} [err] - error infomation\n   * @return {App} this\n   */\n  mockServiceError(service, methodName, err) {\n    if (typeof err === 'string') {\n      err = new Error(err);\n    } else if (!err) {\n      // mockServiceError(service, methodName)\n      err = new Error('mock ' + methodName + ' error');\n    }\n    this.mockService(service, methodName, err);\n    return this;\n  },\n\n  _mockFn(obj, name, data) {\n    const origin = obj[name];\n    assert(is.function(origin), `property ${name} in original object must be function`);\n\n    // keep origin properties' type to support mock multitimes\n    if (!obj[ORIGIN_TYPES]) obj[ORIGIN_TYPES] = {};\n    let type = obj[ORIGIN_TYPES][name];\n    if (!type) {\n      type = obj[ORIGIN_TYPES][name] = is.generatorFunction(origin) || is.asyncFunction(origin) ? 'async' : 'sync';\n    }\n\n    if (is.function(data)) {\n      const fn = data;\n      // if original is generator function or async function\n      // but the mock function is normal function, need to change it return a promise\n      if (type === 'async' &&\n      (!is.generatorFunction(fn) && !is.asyncFunction(fn))) {\n        mm(obj, name, function(...args) {\n          return new Promise(resolve => {\n            resolve(fn.apply(this, args));\n          });\n        });\n        return;\n      }\n\n      mm(obj, name, fn);\n      return;\n    }\n\n    if (type === 'async') {\n      mm(obj, name, () => {\n        return new Promise((resolve, reject) => {\n          if (data instanceof Error) return reject(data);\n          resolve(data);\n        });\n      });\n      return;\n    }\n\n    mm(obj, name, () => {\n      if (data instanceof Error) {\n        throw data;\n      }\n      return data;\n    });\n  },\n\n  /**\n   * mock request\n   * @function App#mockRequest\n   * @param {Request} req - mock request\n   * @return {Request} req\n   */\n  mockRequest(req) {\n    req = Object.assign({}, req);\n    const headers = req.headers || {};\n    for (const key in req.headers) {\n      headers[key.toLowerCase()] = req.headers[key];\n    }\n    if (!headers['x-forwarded-for']) {\n      headers['x-forwarded-for'] = '127.0.0.1';\n    }\n    req.headers = headers;\n    merge(req, {\n      query: {},\n      querystring: '',\n      host: '127.0.0.1',\n      hostname: '127.0.0.1',\n      protocol: 'http',\n      secure: 'false',\n      method: 'GET',\n      url: '/',\n      path: '/',\n      socket: {\n        remoteAddress: '127.0.0.1',\n        remotePort: 7001,\n      },\n    });\n    return req;\n  },\n\n  /**\n   * mock cookies\n   * @function App#mockCookies\n   * @param {Object} cookies - cookie\n   * @return {Context} this\n   */\n  mockCookies(cookies) {\n    if (!cookies) {\n      return this;\n    }\n    const createContext = this.createContext;\n    mm(this, 'createContext', function(req, res) {\n      const ctx = createContext.call(this, req, res);\n      const getCookie = ctx.cookies.get;\n      mm(ctx.cookies, 'get', function(key, opts) {\n        if (cookies[key]) {\n          return cookies[key];\n        }\n        return getCookie.call(this, key, opts);\n      });\n      return ctx;\n    });\n    return this;\n  },\n\n  /**\n   * mock header\n   * @function App#mockHeaders\n   * @param {Object} headers - header 对象\n   * @return {Context} this\n   */\n  mockHeaders(headers) {\n    if (!headers) {\n      return this;\n    }\n    const getHeader = this.request.get;\n    mm(this.request, 'get', function(field) {\n      const header = findHeaders(headers, field);\n      if (header) return header;\n      return getHeader.call(this, field);\n    });\n    return this;\n  },\n\n  /**\n   * mock csrf\n   * @function App#mockCsrf\n   * @return {App} this\n   * @since 1.11\n   */\n  mockCsrf() {\n    mm(this.context, 'assertCSRF', () => {});\n    mm(this.context, 'assertCsrf', () => {});\n    return this;\n  },\n\n  /**\n   * mock httpclient\n   * @function App#mockHttpclient\n   * @param {...any} args - args\n   * @return {Context} this\n   */\n  mockHttpclient(...args) {\n    if (!this._mockHttpclient) {\n      this._mockHttpclient = mockHttpclient(this);\n    }\n    return this._mockHttpclient(...args);\n  },\n\n  mockUrllib(...args) {\n    this.deprecate('[egg-mock] Please use app.mockHttpclient instead of app.mockUrllib');\n    return this.mockHttpclient(...args);\n  },\n\n  /**\n   * get mock httpclient agent\n   * @function App#mockHttpclientAgent\n   * @return {MockAgent} agent\n   */\n  mockAgent() {\n    return mockAgent.getAgent(this);\n  },\n\n  async mockAgentRestore() {\n    await mockAgent.restore();\n  },\n\n  /**\n   * @see mm#restore\n   * @function App#mockRestore\n   */\n  mockRestore: mm.restore,\n\n  /**\n   * @see mm\n   * @function App#mm\n   */\n  mm,\n\n  /**\n   * override loadAgent\n   * @function App#loadAgent\n   */\n  loadAgent() {},\n\n  /**\n   * mock serverEnv\n   * @function App#mockEnv\n   * @param  {String} env - serverEnv\n   * @return {App} this\n   */\n  mockEnv(env) {\n    mm(this.config, 'env', env);\n    mm(this.config, 'serverEnv', env);\n    return this;\n  },\n\n  /**\n   * http request helper\n   * @function App#httpRequest\n   * @return {SupertestRequest} req - supertest request\n   * @see https://github.com/visionmedia/supertest\n   */\n  httpRequest() {\n    return supertestRequest(this);\n  },\n\n  /**\n   * collection logger message, then can be use on `expectLog()`\n   * @param {String|Logger} [logger] - logger instance, default is `ctx.logger`\n   * @function App#mockLog\n   */\n  mockLog(logger) {\n    logger = logger || this.logger;\n    if (typeof logger === 'string') {\n      logger = this.getLogger(logger);\n    }\n    // make sure mock once\n    if (logger._mockLogs) return;\n\n    const transport = new Transport(logger.options);\n    // https://github.com/eggjs/egg-logger/blob/master/lib/logger.js#L64\n    const log = logger.log;\n    mm(logger, '_mockLogs', []);\n    mm(logger, 'log', (level, args, meta) => {\n      const message = transport.log(level, args, meta);\n      logger._mockLogs.push(message);\n      log.apply(logger, [ level, args, meta ]);\n    });\n  },\n\n  __checkExpectLog(expectOrNot, str, logger) {\n    logger = logger || this.logger;\n    if (typeof logger === 'string') {\n      logger = this.getLogger(logger);\n    }\n    const filepath = logger.options.file;\n    let content;\n    if (logger._mockLogs) {\n      content = logger._mockLogs.join('\\n');\n    } else {\n      content = fs.readFileSync(filepath, 'utf8');\n    }\n    let match;\n    let type;\n    if (str instanceof RegExp) {\n      match = str.test(content);\n      type = 'RegExp';\n    } else {\n      match = content.includes(String(str));\n      type = 'String';\n    }\n    if (expectOrNot) {\n      assert(match, `Can't find ${type}:\"${str}\" in ${filepath}, log content: ...${content.substring(content.length - 500)}`);\n    } else {\n      assert(!match, `Find ${type}:\"${str}\" in ${filepath}, log content: ...${content.substring(content.length - 500)}`);\n    }\n  },\n\n  /**\n   * expect str/regexp in the logger, if your server disk is slow, please call `mockLog()` first.\n   * @param {String|RegExp} str - test str or regexp\n   * @param {String|Logger} [logger] - logger instance, default is `ctx.logger`\n   * @function App#expectLog\n   */\n  expectLog(str, logger) {\n    this.__checkExpectLog(true, str, logger);\n  },\n\n  /**\n   * not expect str/regexp in the logger, if your server disk is slow, please call `mockLog()` first.\n   * @param {String|RegExp} str - test str or regexp\n   * @param {String|Logger} [logger] - logger instance, default is `ctx.logger`\n   * @function App#notExpectLog\n   */\n  notExpectLog(str, logger) {\n    this.__checkExpectLog(false, str, logger);\n  },\n\n  backgroundTasksFinished() {\n    const tasks = this._backgroundTasks;\n    debug('waiting %d background tasks', tasks.length);\n    if (tasks.length === 0) return Promise.resolve();\n\n    this._backgroundTasks = [];\n    return Promise.all(tasks).then(() => {\n      debug('finished %d background tasks', tasks.length);\n      if (this._backgroundTasks.length) {\n        debug('new background tasks created: %s', this._backgroundTasks.length);\n        return this.backgroundTasksFinished();\n      }\n    });\n  },\n\n  get _backgroundTasks() {\n    if (!this[BACKGROUND_TASKS]) {\n      this[BACKGROUND_TASKS] = [];\n    }\n    return this[BACKGROUND_TASKS];\n  },\n\n  set _backgroundTasks(tasks) {\n    this[BACKGROUND_TASKS] = tasks;\n  },\n\n};\n\nfunction findHeaders(headers, key) {\n  if (!headers || !key) {\n    return null;\n  }\n  key = key.toLowerCase();\n  for (const headerKey in headers) {\n    if (key === headerKey.toLowerCase()) {\n      return headers[headerKey];\n    }\n  }\n  return null;\n}\n"
  },
  {
    "path": "app/middleware/cluster_app_mock.js",
    "content": "const debug = require('util').debuglog('egg-mock:middleware:cluster_app_mock');\nconst is = require('is-type-of');\nconst co = require('co');\n\nmodule.exports = () => {\n  return function clusterAppMock(ctx, next) {\n    // use originalUrl to make sure other middlewares can't change request url\n    if (ctx.originalUrl !== '/__egg_mock_call_function') return next();\n    debug('%s %s, body: %j', ctx.method, ctx.url, ctx.request.body);\n    const { method, property, args, needResult } = ctx.request.body;\n    if (!method) {\n      ctx.status = 422;\n      ctx.body = {\n        success: false,\n        error: 'Missing method',\n      };\n      return;\n    }\n    if (args && !Array.isArray(args)) {\n      ctx.status = 422;\n      ctx.body = {\n        success: false,\n        error: 'args should be an Array instance',\n      };\n      return;\n    }\n    if (property) {\n      if (!ctx.app[property] || typeof ctx.app[property][method] !== 'function') {\n        ctx.status = 422;\n        ctx.body = {\n          success: false,\n          error: `method \"${method}\" not exists on app.${property}`,\n        };\n        return;\n      }\n    } else {\n      if (typeof ctx.app[method] !== 'function') {\n        ctx.status = 422;\n        ctx.body = {\n          success: false,\n          error: `method \"${method}\" not exists on app`,\n        };\n        return;\n      }\n    }\n\n    debug('call %s with %j', method, args);\n\n    for (let i = 0; i < args.length; i++) {\n      const arg = args[i];\n      if (arg && typeof arg === 'object') {\n        // convert __egg_mock_type back to function\n        if (arg.__egg_mock_type === 'function') {\n          // eslint-disable-next-line\n          args[i] = eval(`(function() { return ${arg.value} })()`);\n        } else if (arg.__egg_mock_type === 'error') {\n          const err = new Error(arg.message);\n          err.name = arg.name;\n          err.stack = arg.stack;\n          for (const key in arg) {\n            if (key !== 'name' && key !== 'message' && key !== 'stack' && key !== '__egg_mock_type') {\n              err[key] = arg[key];\n            }\n          }\n          args[i] = err;\n        }\n      }\n    }\n\n    const target = property ? ctx.app[property] : ctx.app;\n    let fn = target[method];\n    if (is.generatorFunction(fn)) fn = co.wrap(fn);\n    try {\n      Promise.resolve(fn.call(target, ...args)).then(result => {\n        ctx.body = needResult ? { success: true, result } : { success: true };\n      });\n    } catch (err) {\n      ctx.status = 500;\n      ctx.body = { success: false, error: err.message };\n    }\n  };\n};\n"
  },
  {
    "path": "app.js",
    "content": "'use strict';\n\nmodule.exports = app => {\n  // make sure clusterAppMock position before securities\n  const index = app.config.coreMiddleware.indexOf('securities');\n  if (index >= 0) {\n    app.config.coreMiddleware.splice(index, 0, 'clusterAppMock');\n  } else {\n    app.config.coreMiddleware.push('clusterAppMock');\n  }\n};\n"
  },
  {
    "path": "bootstrap.d.ts",
    "content": "import * as assert from 'assert';\nimport { MockApplication, EggMock } from './';\n\nexport {\n  assert\n}\nexport declare const app: MockApplication;\nexport declare const mock: EggMock;\nexport declare const mm: EggMock;\n\n"
  },
  {
    "path": "bootstrap.js",
    "content": "const assert = require('assert');\nconst path = require('path');\nconst mock = require('./index').default;\nconst appHandler = require('./lib/app_handler');\n\nconst { getEggOptions } = require('./lib/utils');\n\nconst options = getEggOptions();\n\n// throw error when an egg plugin test is using bootstrap\nconst pkgInfo = require(path.join(options.baseDir || process.cwd(), 'package.json'));\nif (pkgInfo.eggPlugin) throw new Error('DO NOT USE bootstrap to test plugin');\n\nappHandler.setupApp();\n\nmodule.exports = {\n  assert,\n  get app() {\n    return appHandler.getBootstrapApp();\n  },\n  mock,\n  mm: mock,\n};\n"
  },
  {
    "path": "index.d.ts",
    "content": "import { Application, Context, EggLogger } from 'egg';\nimport { MockMate } from 'mm';\nimport { Test } from 'supertest';\nimport { MockAgent } from 'urllib';\nimport { Suite } from 'mocha';\n\nexport { MockAgent };\n\nexport interface EggTest extends Test {\n  unexpectHeader(name: string, b?: Function): EggTest;\n  expectHeader(name: string, b?: Function): EggTest;\n}\n\nexport type Methods = 'get' | 'post' | 'delete' | 'del' | 'put' | 'head' | 'options' | 'patch' | 'trace' | 'connect';\n\nexport interface BaseMockApplication<T, C> extends Application {\n  ready(): Promise<void>;\n  close(): Promise<void>;\n  callback(): any;\n\n  /**\n   * mock Context\n   */\n  mockContext(data?: any): C;\n\n  /**\n   * mock Context\n   */\n  mockContextScope<R>(fn: (ctx: C) => Promise<R>, data?: any): Promise<R>;\n\n  /**\n   * mock cookie session\n   */\n  mockSession(data: any): T;\n\n  mockCookies(cookies: any): T;\n\n  mockHeaders(headers: any): T;\n\n  /**\n   * Mock service\n   */\n  mockService(service: string, methodName: string, fn: any): T;\n\n  /**\n   * mock service that return error\n   */\n  mockServiceError(service: string, methodName: string, err?: Error): T;\n\n  mockHttpclient(mockUrl: string | RegExp, mockMethod: string | string[], mockResult: MockHttpClientResult): Application;\n\n  mockHttpclient(mockUrl: string | RegExp, mockResult: MockHttpClientResult): Application;\n\n  mockAgent(): MockAgent;\n  mockAgentRestore(): Promise<void>;\n  mockRestore(): Promise<void>;\n\n  /**\n   * mock csrf\n   */\n  mockCsrf(): T;\n\n  /**\n   * http request helper\n   */\n  httpRequest(): {\n    [key in Methods]: (url: string) => EggTest;\n  } & {\n    [key: string]: (url: string) => EggTest;\n  };\n\n  /**\n   * mock logger\n   */\n  mockLog(logger?: EggLogger | string): void;\n  expectLog(expected: string | RegExp, logger?: EggLogger | string): void;\n  notExpectLog(expected: string | RegExp, logger?: EggLogger | string): void;\n\n  /**\n   * background task\n   */\n  backgroundTasksFinished(): Promise<void>;\n}\n\nexport interface ResultObject {\n  data?: string | object | Buffer;\n  status?: number;\n  headers?: any;\n  delay?: number;\n  persist?: boolean;\n  repeats?: number;\n}\n\nexport type ResultFunction = (url?: string, opts?: any) => ResultObject | string | void;\n\nexport type MockHttpClientResult = ResultObject | ResultFunction | string;\n\nexport interface MockOption {\n  /**\n   * The directory of the application\n   */\n  baseDir?: string;\n\n  /**\n   * Custom you plugins\n   */\n  plugins?: any;\n\n  /**\n   * The directory of the egg framework\n   */\n  framework?: string;\n\n  /**\n   * Cache application based on baseDir\n   */\n  cache?: boolean;\n\n  /**\n   * Swtich on process coverage, but it'll be slower\n   */\n  coverage?: boolean;\n\n  /**\n   * Remove $baseDir/logs\n   */\n  clean?: boolean;\n}\n\nexport type EnvType = 'default' | 'test' | 'prod' | 'local' | 'unittest' | string & {};\nexport type LogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'NONE';\n\nexport interface MockApplication extends BaseMockApplication<Application, Context> { }\n\nexport interface EggMock extends MockMate {\n  /**\n   * Create a egg mocked application\n   */\n  app: (option?: MockOption) => MockApplication;\n\n  /**\n   * Create a mock cluster server, but you can't use API in application, you should test using supertest\n   */\n  cluster: (option?: MockOption) => MockApplication;\n\n  /**\n   * mock the serverEnv of Egg\n   */\n  env: (env: EnvType) => void;\n\n  /**\n   * mock console level\n   */\n  consoleLevel: (level: LogLevel) => void;\n\n  /**\n   * set EGG_HOME path\n   */\n  home: (homePath: string) => void;\n\n  /**\n   * restore mock\n   */\n  restore: () => any;\n\n  /**\n   * If you use mm.app instead of egg-mock/bootstrap to bootstrap app.\n   * Should manually call setGetAppCallback,\n   * then egg-mock will inject ctx for each test case\n   * @param cb\n   */\n  setGetAppCallback: (cb: (suite: Suite) => Promise<MockApplication> ) => void;\n}\n\ndeclare const mm: EggMock;\nexport default mm;\n"
  },
  {
    "path": "index.js",
    "content": "const mm = require('mm');\nconst cluster = require('./lib/cluster');\nconst app = require('./lib/app');\nconst mockAgent = require('./lib/mock_agent');\n\n// egg-bin will set this flag to require files for instrument\nif (process.env.EGG_BIN_PREREQUIRE) {\n  require('./lib/prerequire');\n}\n\n/**\n * @namespace mm\n */\n\nfunction mock(...args) {\n  return mm(...args);\n}\nmodule.exports = mock;\nmodule.exports.default = mock;\n\n// inherit & extends mm\nObject.assign(mock, mm, {\n  async restore() {\n    cluster.restore();\n    await Promise.all([ mockAgent.restore(), mm.restore() ]);\n  },\n\n  /**\n   * Create a egg mocked application\n   * @function mm#app\n   * @param {Object} [options]\n   * - {String} baseDir - The directory of the application\n   * - {Object} plugins - Tustom you plugins\n   * - {String} framework - The directory of the egg framework\n   * - {Boolean} [true] cache - Cache application based on baseDir\n   * - {Boolean} [true] coverage - Swtich on process coverage, but it'll be slower\n   * - {Boolean} [true] clean - Remove $baseDir/logs\n   * @return {App} return {@link Application}\n   * @example\n   * ```js\n   * var app = mm.app();\n   * ```\n   */\n  app,\n\n  /**\n   * Create a egg mocked cluster application\n   * @function mm#cluster\n   * @see ClusterApplication\n   */\n  cluster,\n\n  /**\n   * mock the serverEnv of Egg\n   * @member {Function} mm#env\n   * @param {String} env - contain default, test, prod, local, unittest\n   * @see https://github.com/eggjs/egg-core/blob/master/lib/loader/egg_loader.js#L78\n   */\n  env(env) {\n    mm(process.env, 'EGG_MOCK_SERVER_ENV', env);\n    mm(process.env, 'EGG_SERVER_ENV', env);\n  },\n\n  /**\n   * mock console level\n   * @param {String} level - logger level\n   */\n  consoleLevel(level) {\n    level = (level || '').toUpperCase();\n    mm(process.env, 'EGG_LOG', level);\n  },\n\n  home(homePath) {\n    if (homePath) {\n      mm(process.env, 'EGG_HOME', homePath);\n    }\n  },\n\n  setGetAppCallback: require('./lib/app_handler').setGetAppCallback,\n});\n\nprocess.setMaxListeners(100);\n\nprocess.once('SIGQUIT', () => {\n  process.exit(0);\n});\n\nprocess.once('SIGTERM', () => {\n  process.exit(0);\n});\n\nprocess.once('SIGINT', () => {\n  process.exit(0);\n});\n"
  },
  {
    "path": "index.test-d.ts",
    "content": "import { expectType } from 'tsd';\nimport { Application, Context } from 'egg';\nimport { MockApplication, MockAgent, ResultObject } from '.';\nimport { app, mock, mm } from './bootstrap';\n\nexpectType<MockApplication>(app);\nexpectType<Context>(app.currentContext);\nexpectType<Context | undefined>(app.ctxStorage.getStore());\nexpectType<MockApplication>(mock.app());\nexpectType<MockApplication>(mm.app());\n\nexpectType<MockAgent>(mm.app().mockAgent());\n\nexpectType<Application>(mm.app().mockHttpclient('url', 'post', { data: 'ok' }));\nexpectType<Application>(mm.app().mockHttpclient('url', 'post', 'data'));\nexpectType<Application>(mm.app().mockHttpclient('url', {\n  data: 'mock response',\n  repeats: 1,\n}));\nexpectType<Application>(mm.app().mockHttpclient('url', () => {}));\nexpectType<Application>(mm.app().mockHttpclient('url', 'post', () => {}));\nexpectType<Application>(mm.app().mockHttpclient('url', 'get', {\n  data: 'mock response',\n  repeats: 1,\n}));\n\nexpectType<void>(app.mockLog());\nexpectType<void>(app.mockLog('logger'));\nexpectType<void>(app.mockLog(app.logger));\nexpectType<void>(app.expectLog('foo string'));\nexpectType<void>(app.expectLog('foo string', 'coreLogger'));\nexpectType<void>(app.expectLog('foo string', app.coreLogger));\nexpectType<void>(app.expectLog(/foo string/));\nexpectType<void>(app.expectLog(/foo string/, 'coreLogger'));\nexpectType<void>(app.expectLog(/foo string/, app.coreLogger));\nexpectType<void>(mm.env('default'));\nexpectType<void>(mm.env('devserver'));\n\nexpectType<Promise<void>>(app.mockAgentRestore());\nexpectType<Promise<void>>(app.mockRestore());\nexpectType<Promise<void>>(app.mockContextScope(async () => {}));\nexpectType<Promise<void>>(app.mockContextScope(async (ctx) => {}));\n\nexpectType<Promise<void>>(app.backgroundTasksFinished());\n\nconst result: ResultObject = {};\nexpectType<number>(result.status!);\n"
  },
  {
    "path": "lib/agent_handler.js",
    "content": "const debug = require('util').debuglog('egg-mock:lib:agent');\nconst Agent = require('./parallel/agent');\nconst { getEggOptions } = require('./utils');\n\nlet agent;\n\nexports.setupAgent = async () => {\n  debug('setupAgent call, env.ENABLE_MOCHA_PARALLEL: %s, process.env.AUTO_AGENT: %s, agent: %s',\n    process.env.ENABLE_MOCHA_PARALLEL, process.env.AUTO_AGENT, !!agent);\n  if (agent) {\n    await agent.ready();\n    return agent;\n  }\n  if (process.env.ENABLE_MOCHA_PARALLEL && process.env.AUTO_AGENT) {\n    agent = Agent(getEggOptions());\n    await agent.ready();\n  }\n  return agent;\n};\n\nexports.closeAgent = async () => {\n  debug('setupAgent call, agent: %s', !!agent);\n  if (agent) {\n    await agent.close();\n  }\n};\n"
  },
  {
    "path": "lib/app.js",
    "content": "const debug = require('util').debuglog('egg-mock:lib:app');\nconst os = require('os');\nconst path = require('path');\nconst EventEmitter = require('events');\nconst co = require('co');\nconst is = require('is-type-of');\nconst { Ready } = require('get-ready');\nconst { detectPort } = require('detect-port');\nconst ConsoleLogger = require('egg-logger').EggConsoleLogger;\nconst { sleep, rimraf } = require('./utils');\nconst formatOptions = require('./format_options');\nconst context = require('./context');\nconst mockCustomLoader = require('./mock_custom_loader');\nconst mockHttpServer = require('./mock_http_server');\n\nconst consoleLogger = new ConsoleLogger({ level: 'INFO' });\nconst apps = new Map();\nconst INIT = Symbol('init');\nconst APP_INIT = Symbol('appInit');\nconst BIND_EVENT = Symbol('bindEvent');\nconst INIT_ON_LISTENER = Symbol('initOnListener');\nconst INIT_ONCE_LISTENER = Symbol('initOnceListener');\nconst MESSENGER = Symbol('messenger');\nconst MOCK_APP_METHOD = [\n  'ready',\n  'closed',\n  'close',\n  '_agent',\n  '_app',\n  'on',\n  'once',\n  'then',\n];\n\nclass MockApplication extends EventEmitter {\n  constructor(options) {\n    super();\n    this.options = options;\n    this.baseDir = options.baseDir;\n    this.closed = false;\n    this[APP_INIT] = false;\n    this[INIT_ON_LISTENER] = new Set();\n    this[INIT_ONCE_LISTENER] = new Set();\n    Ready.mixin(this);\n    // listen once, otherwise will throw exception when emit error without listenr\n    this.once('error', () => {});\n\n    co(this[INIT].bind(this))\n      .then(() => this.ready(true))\n      .catch(err => {\n        if (!this[APP_INIT]) {\n          this.emit('error', err);\n        }\n        consoleLogger.error(err);\n        this.ready(err);\n      });\n  }\n\n  * [INIT]() {\n    if (this.options.beforeInit) {\n      yield this.options.beforeInit(this);\n      delete this.options.beforeInit;\n    }\n    if (this.options.clean !== false) {\n      const logDir = path.join(this.options.baseDir, 'logs');\n      try {\n        /* istanbul ignore if */\n        if (os.platform() === 'win32') yield sleep(1000);\n        yield rimraf(logDir);\n      } catch (err) {\n        /* istanbul ignore next */\n        console.error(`remove log dir ${logDir} failed: ${err.stack}`);\n      }\n    }\n\n    this.options.clusterPort = yield detectPort();\n    debug('get clusterPort %s', this.options.clusterPort);\n    const egg = require(this.options.framework);\n\n    const Agent = egg.Agent;\n    const agent = this._agent = new Agent(Object.assign({}, this.options));\n    debug('agent instantiate');\n    yield agent.ready();\n    debug('agent ready');\n\n    const Application = bindMessenger(egg.Application, agent);\n    const app = this._app = new Application(Object.assign({}, this.options));\n\n    // https://github.com/eggjs/egg/blob/8bb7c7e7d59d6aeca4b2ed1eb580368dcb731a4d/lib/egg.js#L125\n    // egg single mode mount this at start(), so egg-mock should impel it.\n    app.agent = agent;\n    agent.app = app;\n\n    // egg-mock plugin need to override egg context\n    Object.assign(app.context, context);\n    mockCustomLoader(app);\n\n    debug('app instantiate');\n    this[APP_INIT] = true;\n    debug('this[APP_INIT] = true');\n    this[BIND_EVENT]();\n    debug('http server instantiate');\n    mockHttpServer(app);\n    yield app.ready();\n\n    const msg = {\n      action: 'egg-ready',\n      data: this.options,\n    };\n    app.messenger._onMessage(msg);\n    agent.messenger._onMessage(msg);\n    debug('app ready');\n  }\n\n  [BIND_EVENT]() {\n    for (const args of this[INIT_ON_LISTENER]) {\n      debug('on(%s), use cache and pass to app', args);\n      this._app.on(...args);\n      this.removeListener(...args);\n    }\n    for (const args of this[INIT_ONCE_LISTENER]) {\n      debug('once(%s), use cache and pass to app', args);\n      this._app.on(...args);\n      this.removeListener(...args);\n    }\n  }\n\n  on(...args) {\n    if (this[APP_INIT]) {\n      debug('on(%s), pass to app', args);\n      this._app.on(...args);\n    } else {\n      debug('on(%s), cache it because app has not init', args);\n      this[INIT_ON_LISTENER].add(args);\n      super.on(...args);\n    }\n  }\n\n  once(...args) {\n    if (this[APP_INIT]) {\n      debug('once(%s), pass to app', args);\n      this._app.once(...args);\n    } else {\n      debug('once(%s), cache it because app has not init', args);\n      this[INIT_ONCE_LISTENER].add(args);\n      super.on(...args);\n    }\n  }\n\n  /**\n   * close app\n   * @return {Promise} promise\n   */\n  close() {\n    this.closed = true;\n    const self = this;\n    const baseDir = this.baseDir;\n    return co(function* () {\n      if (self._app) {\n        yield self._app.close();\n      } else {\n        // when app init throws an exception, must wait for app quit gracefully\n        yield sleep(200);\n      }\n\n      if (self._agent) yield self._agent.close();\n\n      apps.delete(baseDir);\n      debug('delete app cache %s, remain %s', baseDir, [ ...apps.keys() ]);\n\n      /* istanbul ignore if */\n      if (os.platform() === 'win32') yield sleep(1000);\n    });\n  }\n}\n\nmodule.exports = function(options) {\n  options = formatOptions(options);\n  if (options.cache && apps.has(options.baseDir)) {\n    const app = apps.get(options.baseDir);\n    // return cache when it hasn't been killed\n    if (!app.closed) {\n      return app;\n    }\n    // delete the cache when it's closed\n    apps.delete(options.baseDir);\n  }\n\n  let app = new MockApplication(options);\n  app = new Proxy(app, {\n    get(target, prop) {\n      // don't delegate properties on MockApplication\n      if (MOCK_APP_METHOD.includes(prop)) return getProperty(target, prop);\n      if (!target[APP_INIT]) throw new Error(`can't get ${prop} before ready`);\n      // it's asynchronous when agent and app are loading,\n      // so should get the properties after loader ready\n      debug('proxy handler.get %s', prop);\n      return target._app[prop];\n    },\n    set(target, prop, value) {\n      if (MOCK_APP_METHOD.includes(prop)) return true;\n      if (!target[APP_INIT]) throw new Error(`can't set ${prop} before ready`);\n      debug('proxy handler.set %s', prop);\n      target._app[prop] = value;\n      return true;\n    },\n    defineProperty(target, prop, descriptor) {\n      // can't define properties on MockApplication\n      if (MOCK_APP_METHOD.includes(prop)) return true;\n      if (!target[APP_INIT]) throw new Error(`can't defineProperty ${prop} before ready`);\n      debug('proxy handler.defineProperty %s', prop);\n      Object.defineProperty(target._app, prop, descriptor);\n      return true;\n    },\n    deleteProperty(target, prop) {\n      // can't delete properties on MockApplication\n      if (MOCK_APP_METHOD.includes(prop)) return true;\n      if (!target[APP_INIT]) throw new Error(`can't delete ${prop} before ready`);\n      debug('proxy handler.deleteProperty %s', prop);\n      delete target._app[prop];\n      return true;\n    },\n    getOwnPropertyDescriptor(target, prop) {\n      if (MOCK_APP_METHOD.includes(prop)) return Object.getOwnPropertyDescriptor(target, prop);\n      if (!target[APP_INIT]) throw new Error(`can't getOwnPropertyDescriptor ${prop} before ready`);\n      debug('proxy handler.getOwnPropertyDescriptor %s', prop);\n      return Object.getOwnPropertyDescriptor(target._app, prop);\n    },\n    getPrototypeOf(target) {\n      if (!target[APP_INIT]) throw new Error('can\\'t getPrototypeOf before ready');\n      debug('proxy handler.getPrototypeOf %s');\n      return Object.getPrototypeOf(target._app);\n    },\n  });\n\n  apps.set(options.baseDir, app);\n  return app;\n};\n\nfunction getProperty(target, prop) {\n  const member = target[prop];\n  if (is.function(member)) {\n    return member.bind(target);\n  }\n  return member;\n}\n\n\nfunction bindMessenger(Application, agent) {\n  const agentMessenger = agent.messenger;\n  return class MessengerApplication extends Application {\n    constructor(options) {\n      super(options);\n\n      // enable app to send to a random agent\n      this.messenger.sendRandom = (action, data) => {\n        this.messenger.sendToAgent(action, data);\n      };\n      // enable agent to send to a random app\n      agentMessenger.on('egg-ready', () => {\n        agentMessenger.sendRandom = (action, data) => {\n          agentMessenger.sendToApp(action, data);\n        };\n      });\n\n      agentMessenger.send = new Proxy(agentMessenger.send, {\n        apply: this._sendMessage.bind(this),\n      });\n    }\n    _sendMessage(target, thisArg, [ action, data, to ]) {\n      const appMessenger = this.messenger;\n      setImmediate(() => {\n\n        if (to === 'app') {\n          appMessenger._onMessage({ action, data });\n        } else {\n          agentMessenger._onMessage({ action, data });\n        }\n      });\n    }\n    get messenger() {\n      return this[MESSENGER];\n    }\n    set messenger(m) {\n      m.send = new Proxy(m.send, {\n        apply: this._sendMessage.bind(this),\n      });\n      this[MESSENGER] = m;\n    }\n\n    get [Symbol.for('egg#eggPath')]() { return path.join(__dirname, 'tmp'); }\n  };\n}\n"
  },
  {
    "path": "lib/app_handler.js",
    "content": "const debug = require('util').debuglog('egg-mock:bootstrap:app_handler');\nconst mockParallelApp = require('./parallel/app');\nconst { setupAgent } = require('./agent_handler');\nconst mock = require('../index').default;\nconst { getEggOptions } = require('./utils');\n\nlet app;\n\nexports.setupApp = () => {\n  if (app) {\n    debug('return exists app');\n    return app;\n  }\n\n  const options = getEggOptions();\n  debug('env.ENABLE_MOCHA_PARALLEL: %s, process.env.AUTO_AGENT: %s',\n    process.env.ENABLE_MOCHA_PARALLEL, process.env.AUTO_AGENT);\n  if (process.env.ENABLE_MOCHA_PARALLEL && process.env.AUTO_AGENT) {\n    // setup agent first\n    app = mockParallelApp({\n      ...options,\n      beforeInit: async _app => {\n        const agent = await setupAgent();\n        _app.options.clusterPort = agent.options.clusterPort;\n        debug('mockParallelApp beforeInit get clusterPort: %s', _app.options.clusterPort);\n      },\n    });\n    debug('mockParallelApp app: %s', !!app);\n  } else {\n    app = mock.app(options);\n    if (typeof beforeAll === 'function') {\n      // jest\n      beforeAll(() => app.ready());\n      afterEach(() => app.backgroundTasksFinished());\n      afterEach(mock.restore);\n    }\n  }\n};\n\nlet getAppCallback;\n\nexports.setGetAppCallback = cb => {\n  getAppCallback = cb;\n};\n\nexports.getApp = async (suite, test) => {\n  if (getAppCallback) {\n    return getAppCallback(suite, test);\n  }\n  if (app) {\n    await app.ready();\n  }\n  return app;\n};\n\nexports.getBootstrapApp = () => {\n  return app;\n};\n"
  },
  {
    "path": "lib/cluster.js",
    "content": "const debug = require('util').debuglog('egg-mock:cluster');\nconst path = require('path');\nconst os = require('os');\nconst childProcess = require('child_process');\nconst Coffee = require('coffee').Coffee;\nconst { Ready } = require('get-ready');\nconst co = require('co');\nconst awaitEvent = require('await-event');\nconst supertestRequest = require('./supertest');\nconst { sleep, rimrafSync } = require('./utils');\nconst formatOptions = require('./format_options');\n\nconst clusters = new Map();\nconst serverBin = path.join(__dirname, 'start-cluster');\nconst requestCallFunctionFile = path.join(__dirname, 'request_call_function.js');\nlet masterPort = 17000;\n\n/**\n * A cluster version of egg.Application, you can test with supertest\n * @example\n * ```js\n * const mm = require('mm');\n * const request = require('supertest');\n *\n * describe('ClusterApplication', () => {\n *   let app;\n *   before(function (done) {\n *     app = mm.cluster({ baseDir });\n *     app.ready(done);\n *   });\n *\n *   after(function () {\n *     app.close();\n *   });\n *\n *   it('should 200', function (done) {\n *     request(app.callback())\n *     .get('/')\n *     .expect(200, done);\n *   });\n * });\n */\nclass ClusterApplication extends Coffee {\n  /**\n   * @class\n   * @param {Object} options\n   * - {String} baseDir - The directory of the application\n   * - {Object} plugins - Tustom you plugins\n   * - {String} framework - The directory of the egg framework\n   * - {Boolean} [cache=true]  - Cache application based on baseDir\n   * - {Boolean} [coverage=true]  - Swtich on process coverage, but it'll be slower\n   * - {Boolean} [clean=true]  - Remove $baseDir/logs\n   * - {Object}  [opt] - opt pass to coffee, such as { execArgv: ['--debug'] }\n   * ```\n   */\n  constructor(options) {\n    const opt = options.opt;\n    delete options.opt;\n\n    // incremental port\n    options.port = options.port || ++masterPort;\n    // Set 1 worker when test\n    if (!options.workers) options.workers = 1;\n\n    const args = [ JSON.stringify(options) ];\n    debug('fork %s, args: %s, opt: %j', serverBin, args.join(' '), opt);\n    super({\n      method: 'fork',\n      cmd: serverBin,\n      args,\n      opt,\n    });\n\n    Ready.mixin(this);\n\n    this.port = options.port;\n    this.baseDir = options.baseDir;\n\n    // print stdout and stderr when DEBUG, otherwise stderr.\n    this.debug(process.env.DEBUG ? 0 : 2);\n\n    // disable coverage\n    if (options.coverage === false) {\n      this.coverage(false);\n    }\n\n    process.nextTick(() => {\n      this.proc.on('message', msg => {\n        // 'egg-ready' and { action: 'egg-ready' }\n        const action = msg && msg.action ? msg.action : msg;\n        switch (action) {\n          case 'egg-ready':\n            this.emit('close', 0);\n            break;\n          case 'app-worker-died':\n          case 'agent-worker-died':\n            this.emit('close', 1);\n            break;\n          default:\n            // ignore it\n            break;\n        }\n      });\n    });\n\n    this.end(() => this.ready(true));\n  }\n\n  /**\n   * the process that forked\n   * @member {ChildProcess}\n   */\n  get process() {\n    return this.proc;\n  }\n\n  /**\n   * Compatible API for supertest\n   * @return {ClusterApplication} return the instance\n   */\n  callback() {\n    return this;\n  }\n\n  /**\n   * Compatible API for supertest\n   * @member {String} url\n   * @private\n   */\n  get url() {\n    return 'http://127.0.0.1:' + this.port;\n  }\n\n  /**\n   * Compatible API for supertest\n   * @return {Object}\n   *  - {Number} port\n   * @private\n   */\n  address() {\n    return {\n      port: this.port,\n    };\n  }\n\n  /**\n   * Compatible API for supertest\n   * @return {ClusterApplication} return the instance\n   * @private\n   */\n  listen() {\n    return this;\n  }\n\n  /**\n   * kill the process\n   * @return {Promise} promise\n   */\n  close() {\n    this.closed = true;\n\n    const proc = this.proc;\n    const baseDir = this.baseDir;\n    return co(function* () {\n      if (proc.connected) {\n        proc.kill('SIGTERM');\n        yield awaitEvent.call(proc, 'exit');\n      }\n\n      clusters.delete(baseDir);\n      debug('delete cluster cache %s, remain %s', baseDir, [ ...clusters.keys() ]);\n\n      /* istanbul ignore if */\n      if (os.platform() === 'win32') yield sleep(1000);\n    });\n  }\n\n  // mock app.router.pathFor(name) api\n  get router() {\n    const that = this;\n    return {\n      pathFor(url) {\n        return that._callFunctionOnAppWorker('pathFor', [ url ], 'router', true);\n      },\n    };\n  }\n\n  /**\n   * collection logger message, then can be use on `expectLog()`\n   * it's different from `app.expectLog()`, only support string params.\n   *\n   * @param {String} [logger] - logger instance name, default is `logger`\n   * @function ClusterApplication#expectLog\n   */\n  mockLog(logger) {\n    logger = logger || 'logger';\n    this._callFunctionOnAppWorker('mockLog', [ logger ], null, true);\n  }\n\n  /**\n   * expect str in the logger\n   * it's different from `app.expectLog()`, only support string params.\n   *\n   * @param {String} str - test str\n   * @param {String} [logger] - logger instance name, default is `logger`\n   * @function ClusterApplication#expectLog\n   */\n  expectLog(str, logger) {\n    logger = logger || 'logger';\n    this._callFunctionOnAppWorker('expectLog', [ str, logger ], null, true);\n  }\n\n  /**\n   * not expect str in the logger\n   * it's different from `app.notExpectLog()`, only support string params.\n   *\n   * @param {String} str - test str\n   * @param {String} [logger] - logger instance name, default is `logger`\n   * @function ClusterApplication#notExpectLog\n   */\n  notExpectLog(str, logger) {\n    logger = logger || 'logger';\n    this._callFunctionOnAppWorker('notExpectLog', [ str, logger ], null, true);\n  }\n\n  httpRequest() {\n    return supertestRequest(this);\n  }\n\n  _callFunctionOnAppWorker(method, args = [], property = undefined, needResult = false) {\n    for (let i = 0; i < args.length; i++) {\n      const arg = args[i];\n      if (typeof arg === 'function') {\n        args[i] = {\n          __egg_mock_type: 'function',\n          value: arg.toString(),\n        };\n      } else if (arg instanceof Error) {\n        const errObject = {\n          __egg_mock_type: 'error',\n          name: arg.name,\n          message: arg.message,\n          stack: arg.stack,\n        };\n        for (const key in arg) {\n          if (key !== 'name' && key !== 'message' && key !== 'stack') {\n            errObject[key] = arg[key];\n          }\n        }\n        args[i] = errObject;\n      }\n    }\n    const data = {\n      port: this.port,\n      method,\n      args,\n      property,\n      needResult,\n    };\n    const child = childProcess.spawnSync(process.execPath, [\n      requestCallFunctionFile,\n      JSON.stringify(data),\n    ], {\n      stdio: 'pipe',\n    });\n    if (child.stderr && child.stderr.length > 0) {\n      console.error(child.stderr.toString());\n    }\n\n    let result;\n    if (child.stdout && child.stdout.length > 0) {\n      if (needResult) {\n        result = JSON.parse(child.stdout.toString());\n      } else {\n        console.error(child.stdout.toString());\n      }\n    }\n\n    if (child.status !== 0) {\n      throw new Error(child.stderr.toString());\n    }\n    if (child.error) {\n      throw child.error;\n    }\n\n    return result;\n  }\n}\n\nmodule.exports = options => {\n  options = formatOptions(options);\n  if (options.cache && clusters.has(options.baseDir)) {\n    const clusterApp = clusters.get(options.baseDir);\n    // return cache when it hasn't been killed\n    if (!clusterApp.closed) {\n      return clusterApp;\n    }\n\n    // delete the cache when it's closed\n    clusters.delete(options.baseDir);\n  }\n\n  if (options.clean !== false) {\n    const logDir = path.join(options.baseDir, 'logs');\n    try {\n      rimrafSync(logDir);\n    } catch (err) {\n      /* istanbul ignore next */\n      console.error(`remove log dir ${logDir} failed: ${err.stack}`);\n    }\n  }\n\n  let clusterApp = new ClusterApplication(options);\n  clusterApp = new Proxy(clusterApp, {\n    get(target, prop) {\n      debug('proxy handler.get %s', prop);\n      // proxy mockXXX function to app worker\n      const method = prop;\n      if (typeof method === 'string' && /^mock\\w+$/.test(method) && target[method] === undefined) {\n        return function mockProxy(...args) {\n          return target._callFunctionOnAppWorker(method, args, null, true);\n        };\n      }\n\n      return target[prop];\n    },\n  });\n\n  clusters.set(options.baseDir, clusterApp);\n  return clusterApp;\n};\n\n// export to let mm.restore() worked\nmodule.exports.restore = () => {\n  for (const clusterApp of clusters.values()) {\n    clusterApp.mockRestore();\n  }\n};\n\n// ensure to close App process on test exit.\nprocess.on('exit', () => {\n  for (const clusterApp of clusters.values()) {\n    clusterApp.close();\n  }\n});\n"
  },
  {
    "path": "lib/context.js",
    "content": "'use strict';\n\n// try to use eggUtils.getCalleeFromStack\n// ignore it if egg-core module not found\nlet eggUtils;\ntry {\n  eggUtils = require('egg-core').utils;\n  if (!eggUtils) {\n    // try to support egg-core@3\n    eggUtils = require('egg-core/lib/utils');\n  }\n} catch (_) {\n  // ignore eggUtils\n}\n\nmodule.exports = {\n  runInBackground(scope) {\n    /* istanbul ignore next */\n    const taskName = scope._name || scope.name || (eggUtils && eggUtils.getCalleeFromStack(true));\n    if (taskName) {\n      scope._name = taskName;\n    }\n\n    const promise = this._runInBackground(scope);\n    this.app._backgroundTasks.push(promise);\n  },\n};\n"
  },
  {
    "path": "lib/format_options.js",
    "content": "const debug = require('util').debuglog('mm');\nconst path = require('path');\nconst mm = require('mm');\nconst utils = require('@eggjs/utils');\n\n/**\n * format the options\n * @param  {Object} options - options\n * @return {Object} options\n */\nmodule.exports = function formatOptions(options) {\n  const defaults = {\n    baseDir: process.cwd(),\n    cache: true,\n    coverage: true,\n    clean: true,\n  };\n  options = Object.assign({}, defaults, options);\n\n  // relative path to test/fixtures\n  // ```js\n  // formatOptions({ baseDir: 'app' }); // baseDir => $PWD/test/fixtures/app\n  // ```\n  if (!path.isAbsolute(options.baseDir)) {\n    options.baseDir = path.join(process.cwd(), 'test/fixtures', options.baseDir);\n  }\n\n  let framework = options.framework || options.customEgg;\n  // test for framework\n  if (framework === true) {\n    framework = process.cwd();\n    // disable plugin test when framework test\n    options.plugin = false;\n  } else {\n    // it will throw when framework is not found\n    framework = utils.getFrameworkPath({ framework, baseDir: options.baseDir });\n  }\n  options.customEgg = options.framework = framework;\n\n  const plugins = options.plugins = options.plugins || {};\n\n  // add self as a plugin\n  plugins['egg-mock'] = {\n    enable: true,\n    path: path.join(__dirname, '..'),\n  };\n\n  // test for plugin\n  if (options.plugin !== false) {\n    // add self to plugin list\n    const pkgPath = path.join(process.cwd(), 'package.json');\n    const pluginName = getPluginName(pkgPath);\n    if (options.plugin && !pluginName) {\n      throw new Error(`should set eggPlugin in ${pkgPath}`);\n    }\n    if (pluginName) {\n      plugins[pluginName] = {\n        enable: true,\n        path: process.cwd(),\n      };\n    }\n  }\n\n  // mock HOME as baseDir, but ignore if it has been mocked\n  const env = process.env.EGG_SERVER_ENV;\n  if (!mm.isMocked(process.env, 'HOME') &&\n    (env === 'default' || env === 'test' || env === 'prod')) {\n    mm(process.env, 'HOME', options.baseDir);\n  }\n\n  // disable cache after call mm.env(),\n  // otherwise it will use cache and won't load again.\n  if (process.env.EGG_MOCK_SERVER_ENV) {\n    options.cache = false;\n  }\n\n  debug('format options: %j', options);\n  return options;\n};\n\nfunction getPluginName(pkgPath) {\n  try {\n    const pkg = require(pkgPath);\n    if (pkg.eggPlugin && pkg.eggPlugin.name) {\n      return pkg.eggPlugin.name;\n    }\n  } catch (_) {\n    // ignore\n  }\n}\n"
  },
  {
    "path": "lib/http_test.js",
    "content": "'use strict';\n\nconst Test = require('supertest').Test;\n\nclass EggTest extends Test {\n  /**\n   * Unexpectations:\n   *\n   *   .unexpectHeader('Content-Type')\n   *   .unexpectHeader('Content-Type', fn)\n   *\n   * @return {EggTest}\n   * @public\n   */\n\n  unexpectHeader(name, b) {\n    if (typeof b === 'function') {\n      this.end(b);\n    }\n\n    // header\n    if (typeof name === 'string') {\n      this._asserts.push(this._unexpectHeader.bind(this, name));\n    }\n    return this;\n  }\n\n  /**\n   * Expectations:\n   *\n   *   .expectHeader('Content-Type')\n   *   .expectHeader('Content-Type', fn)\n   *\n   * @return {EggTest}\n   * @public\n   */\n\n  expectHeader(name, b) {\n    if (typeof b === 'function') {\n      this.end(b);\n    }\n\n    // header\n    if (typeof name === 'string') {\n      this._asserts.push(this._expectHeader.bind(this, name));\n    }\n    return this;\n  }\n\n  _unexpectHeader(name, res) {\n    const actual = res.headers[name.toLowerCase()];\n    if (actual) {\n      return new Error('unexpected \"' + name + '\" header field, got \"' + actual + '\"');\n    }\n  }\n\n  _expectHeader(name, res) {\n    const actual = res.headers[name.toLowerCase()];\n    if (!actual) {\n      return new Error('expected \"' + name + '\" header field');\n    }\n  }\n}\n\nmodule.exports = EggTest;\n"
  },
  {
    "path": "lib/inject_context.js",
    "content": "const assert = require('assert');\nconst debug = require('util').debuglog('egg-mock:inject_context');\nconst MOCHA_SUITE_APP = Symbol.for('mocha#suite#app');\nconst appHandler = require('./app_handler');\n\n/**\n * Monkey patch the mocha instance with egg context.\n *\n * @param {Function} mocha -\n */\nfunction injectContext(mocha) {\n  if (!mocha || mocha._injectContextLoaded) {\n    return;\n  }\n\n  const { Runner } = mocha;\n  const runSuite = Runner.prototype.runSuite;\n  const runTests = Runner.prototype.runTests;\n\n  function getTestTitle(suite, test) {\n    const suiteTitle = suite.root ? 'root suite' : suite.title;\n    if (!test) {\n      return `\"${suiteTitle}\"`;\n    }\n    return `\"${suiteTitle} - ${test.title}\"`;\n  }\n\n  // Inject ctx for before/after.\n  Runner.prototype.runSuite = async function(suite, fn) {\n    debug('run suite: %s', suite.title);\n    let app;\n    const self = this;\n    try {\n      app = await appHandler.getApp(suite);\n      debug('get app: %s', !!app);\n      await app.ready();\n    } catch {\n      // 可能 app.ready 时报错，不使用失败的 app\n      app = null;\n    }\n    if (!app) {\n      // app 不存在，直接跳过，在 beforeEach 的 hook 中会报错\n      // 确保不打乱 mocha 的顺序，防止 mocha 内部状态错误\n      return runSuite.call(self, suite, fn);\n    }\n    let errSuite;\n    try {\n      suite.ctx[MOCHA_SUITE_APP] = app;\n      const mockContextFun = app.mockModuleContextScope || app.mockContextScope;\n      await mockContextFun.call(app, async function() {\n        await new Promise(resolve => {\n          runSuite.call(self, suite, aErrSuite => {\n            errSuite = aErrSuite;\n            resolve();\n          });\n        });\n      });\n    } catch (err) {\n      // mockContext 失败后动态注册一个 beforeAll hook\n      // 快速失败，直接阻塞后续用例\n      suite.beforeAll('egg-mock-mock-ctx-failed', async () => {\n        throw err;\n      });\n      return runSuite.call(self, suite, aErrSuite => {\n        return fn(aErrSuite);\n      });\n    }\n    return fn(errSuite);\n  };\n\n  // Inject ctx for beforeEach/it/afterEach.\n  // And ctx with before/after is not same as beforeEach/it/afterEach.\n  Runner.prototype.runTests = async function(suite, fn) {\n    const tests = suite.tests.slice();\n    if (!tests.length) {\n      return runTests.call(this, suite, fn);\n    }\n\n    const app = suite.ctx[MOCHA_SUITE_APP];\n\n    const self = this;\n    if (!app) {\n      return runTests.call(self, suite, fn);\n    }\n\n    function done(errSuite) {\n      suite.tests = tests;\n      return fn(errSuite);\n    }\n\n    async function next(i) {\n      const test = tests[i];\n      if (!test) {\n        return done();\n      }\n      suite.tests = [ test ];\n\n      let app;\n      try {\n        app = await appHandler.getApp(suite, test);\n        assert(app, `not found app for test ${getTestTitle(suite, test)}`);\n        await app.ready();\n      } catch (err) {\n        self.fail(test, err);\n        return next(i + 1);\n      }\n\n      try {\n        const mockContextFun = app.mockModuleContextScope || app.mockContextScope;\n        await mockContextFun.call(app, async function() {\n          return await new Promise(resolve => {\n            runTests.call(self, suite, () => {\n              return resolve();\n            });\n          });\n        });\n      } catch (err) {\n        self.fail(test, err);\n        return next(i + 1);\n      }\n      return next(i + 1);\n    }\n    next(0).catch(err => {\n      self.fail(suite, err);\n      done(suite);\n    });\n  };\n\n  mocha._injectContextLoaded = true;\n}\n\nmodule.exports = injectContext;\n"
  },
  {
    "path": "lib/mock_agent.js",
    "content": "const { debuglog } = require('util');\nlet { MockAgent, setGlobalDispatcher, getGlobalDispatcher } = require('urllib');\nif (typeof getGlobalDispatcher === 'undefined') {\n  let urllibNext;\n  // https://github.com/eggjs/egg/blob/3.x/package.json#L59\n  try {\n    // try to use urllib4\n    urllibNext = require('urllib4');\n  } catch {\n    // try to use urllib-next\n    try {\n      urllibNext = require('urllib-next');\n    } catch {\n      throw new Error('Please install urllib@4');\n    }\n  }\n  MockAgent = urllibNext.MockAgent;\n  setGlobalDispatcher = urllibNext.setGlobalDispatcher;\n  getGlobalDispatcher = urllibNext.getGlobalDispatcher;\n}\n\nconst debug = debuglog('egg-mock:lib:mock_agent');\n\nlet _mockAgent;\nlet _global;\nconst APP_HTTPCLIENT_AGENT = Symbol('app.httpclient.agent');\nconst httpClients = [];\n\nmodule.exports = {\n  getAgent(app) {\n    if (!_global) {\n      _global = getGlobalDispatcher();\n    }\n    if (!app?.httpclient?.[APP_HTTPCLIENT_AGENT] && typeof app?.httpclient?.getDispatcher === 'function') {\n      // save the raw dispatcher\n      app.httpclient[APP_HTTPCLIENT_AGENT] = app.httpclient.getDispatcher();\n      httpClients.push(app.httpclient);\n      debug('add new httpClient, size: %d', httpClients.length);\n    }\n    if (!_mockAgent) {\n      _mockAgent = new MockAgent();\n      setGlobalDispatcher(_mockAgent);\n      if (typeof app?.httpclient?.setDispatcher === 'function') {\n        app.httpclient.setDispatcher(_mockAgent);\n      }\n    }\n    return _mockAgent;\n  },\n  async restore() {\n    if (!_mockAgent) return;\n    if (_global) {\n      setGlobalDispatcher(_global);\n    }\n    for (const httpClient of httpClients) {\n      httpClient.setDispatcher(httpClient[APP_HTTPCLIENT_AGENT]);\n    }\n    debug('restore httpClient, size: %d', httpClients.length);\n    const agent = _mockAgent;\n    _mockAgent = null;\n    await agent.close();\n  },\n};\n"
  },
  {
    "path": "lib/mock_custom_loader.js",
    "content": "'use strict';\n\nmodule.exports = app => {\n  const customLoader = app.config.customLoader;\n  if (!customLoader) return;\n\n  for (const field of Object.keys(customLoader)) {\n    const loaderConfig = Object.assign({}, customLoader[field]);\n    loaderConfig.field = field;\n    addMethod(loaderConfig);\n  }\n\n  function addMethod(loaderConfig) {\n    const field = loaderConfig.field;\n    const appMethodName = 'mock' + field.replace(/^[a-z]/i, s => s.toUpperCase());\n    if (app[appMethodName]) {\n      app.coreLogger.warn('Can\\'t override app.%s', appMethodName);\n      return;\n    }\n    app[appMethodName] = function(service, methodName, fn) {\n      if (typeof service === 'string') {\n        const arr = service.split('.');\n        service = loaderConfig.inject === 'ctx' ? this[field + 'Classes'] : this[field];\n        for (const key of arr) {\n          service = service[key];\n        }\n        service = service.prototype || service;\n      }\n      this._mockFn(service, methodName, fn);\n      return this;\n    };\n  }\n};\n"
  },
  {
    "path": "lib/mock_http_server.js",
    "content": "'use strict';\n\nconst http = require('http');\nconst SERVER = Symbol('http_server');\n\nmodule.exports = app => {\n  let server = app[SERVER] || app.callback();\n  if (typeof server === 'function') {\n    server = http.createServer(server);\n    // cache server, avoid create many times\n    app[SERVER] = server;\n    // emit server event just like egg-cluster does\n    // https://github.com/eggjs/egg-cluster/blob/master/lib/app_worker.js#L52\n    app.emit('server', server);\n  }\n  return server;\n};\n"
  },
  {
    "path": "lib/mock_httpclient.js",
    "content": "const mm = require('mm');\nconst extend = require('extend2');\nconst is = require('is-type-of');\nconst mockAgent = require('./mock_agent');\n\nfunction matchMethod(mockMethods, method) {\n  return mockMethods.some(m => m === '*' || m === method);\n}\nfunction matchUrl(mockUrl, url) {\n  if (url === mockUrl) return true;\n  if (mockUrl instanceof RegExp && url.match(mockUrl)) return true;\n  return false;\n}\n\nfunction normalizeResult(result) {\n  if (is.string(result)) {\n    result = { data: result };\n  }\n\n  if (!result.status) {\n    result.status = 200;\n  }\n\n  result.data = result.data || '';\n  if (Buffer.isBuffer(result.data)) {\n    // do nothing\n  } else if (typeof result.data === 'object') {\n    // json\n    result.data = Buffer.from(JSON.stringify(result.data));\n  } else if (typeof result.data === 'string') {\n    // string\n    result.data = Buffer.from(result.data);\n  } else {\n    throw new Error('`mockResult.data` must be buffer, string or json');\n  }\n\n  if (!result.res) {\n    result.res = {\n      status: result.status,\n    };\n  }\n  result.responseSize = result.responseSize || 0;\n  if (result.data) {\n    result.responseSize = result.data.length;\n  }\n  result.headers = result.headers || {};\n  return result;\n}\n\nmodule.exports = app => {\n  /**\n   * mock httpclient\n   * @function mockHttpclient\n   * @param {String} mockUrl - url\n   * @param {String|Array} mockMethod - http method, default is '*'\n   * @param {Object|Function} mockResult - you data\n   *   - data - buffer / string / json\n   *   - status - http status\n   *   - headers - response header\n   *   - delay - delay the associated reply by a set amount in ms.\n   *   - persist - any matching request will always reply with the defined response indefinitely, default is true\n   *   - repeats - number, any matching request will reply with the defined response a fixed amount of times\n   * @return {Context} this\n   */\n\n  const MOCK_CONFIGS = Symbol('MOCK_CONFIGS');\n  const MOCK_CONFIG_INDEX = Symbol('MOCK_CONFIG_INDEX');\n\n  return function mockHttpclient(mockUrl, mockMethod, mockResult) {\n    if (!mockResult) {\n      // app.mockHttpclient(mockUrl, mockResult)\n      mockResult = mockMethod;\n      mockMethod = '*';\n    }\n    if (!Array.isArray(mockMethod)) mockMethod = [ mockMethod ];\n    mockMethod = mockMethod.map(method => (method || 'GET').toUpperCase());\n\n    if (app.config.httpclient.useHttpClientNext) {\n      // use MockAgent on undici\n      let mockConfigs = app[MOCK_CONFIGS];\n      if (!mockConfigs) {\n        mockConfigs = [];\n        mm(app, MOCK_CONFIGS, mockConfigs);\n      }\n\n      let mockConfigIndex = -1;\n      let origin = mockUrl;\n      let pathname = mockUrl;\n      if (typeof mockUrl === 'string') {\n        const urlObject = new URL(mockUrl);\n        origin = urlObject.origin;\n        const orginalPathname = urlObject.pathname;\n        pathname = path => {\n          if (path === orginalPathname) return true;\n          // should match /foo?a=1 including query\n          if (path.includes('?')) return path.startsWith(orginalPathname);\n          return false;\n        };\n      } else if (mockUrl instanceof RegExp) {\n        let requestOrigin = '';\n        origin = value => {\n          requestOrigin = value;\n          return true;\n        };\n        pathname = path => {\n          for (const config of mockConfigs) {\n            if (config.mockUrl.test(`${requestOrigin}${path}`)) {\n              mm(app, MOCK_CONFIG_INDEX, config.mockConfigIndex);\n              return true;\n            }\n          }\n          return false;\n        };\n        mockConfigIndex = mockConfigs.length;\n        mockConfigs.push({ mockUrl, mockResult, mockConfigIndex });\n      }\n      const mockPool = mockAgent.getAgent(app).get(origin);\n      // persist default is true\n      const persist = typeof mockResult?.persist === 'boolean' ? mockResult?.persist : true;\n      mockMethod.forEach(function(method) {\n        if (method === '*') {\n          method = () => true;\n        }\n        const mockScope = mockPool.intercept({\n          path: pathname,\n          method,\n        }).reply(options => {\n          // not support mockResult as an async function\n          const requestUrl = `${options.origin}${options.path}`;\n          let mockRequestResult;\n          if (mockConfigIndex >= 0) {\n            mockResult = mockConfigs[app[MOCK_CONFIG_INDEX]].mockResult;\n            mockRequestResult = is.function(mockResult) ? mockResult(requestUrl, options) : mockResult;\n          } else {\n            mockRequestResult = is.function(mockResult) ? mockResult(requestUrl, options) : mockResult;\n          }\n          const result = extend(true, {}, normalizeResult(mockRequestResult));\n          return {\n            statusCode: result.status,\n            data: result.data,\n            responseOptions: {\n              headers: result.headers,\n            },\n          };\n        });\n        if (mockResult?.delay > 0) {\n          mockScope.delay(mockResult.delay);\n        }\n        if (persist) {\n          mockScope.persist();\n        } else if (mockResult?.repeats > 0) {\n          mockScope.times(mockResult.repeats);\n        }\n      });\n      return;\n    }\n\n    const httpclient = app.httpclient;\n\n    const rawRequest = httpclient.request;\n\n    mm(httpclient, 'requestThunk', _request);\n    mm(httpclient, 'request', _request);\n    mm(httpclient, 'curl', _request);\n\n    return app;\n\n    // support generator rather than callback and promise\n    async function _request(url, opt) {\n      opt = opt || {};\n      opt.method = (opt.method || 'GET').toUpperCase();\n      opt.headers = opt.headers || {};\n      if (matchUrl(mockUrl, url) && matchMethod(mockMethod, opt.method)) {\n        let mockRequestResult = is.function(mockResult) ? mockResult(url, opt) : mockResult;\n        // support mockResult as an async function\n        if (is.promise(mockRequestResult)) mockRequestResult = await mockRequestResult;\n        const result = extend(true, {}, normalizeResult(mockRequestResult));\n        const response = {\n          status: result.status,\n          statusCode: result.status,\n          headers: result.headers,\n          size: result.responseSize,\n          aborted: false,\n          rt: 1,\n          keepAliveSocket: result.keepAliveSocket || false,\n        };\n\n        httpclient.emit('request', {\n          reqId: Date.now(),\n          url,\n          args: opt,\n          ctx: opt.ctx,\n        });\n\n        httpclient.emit('response', {\n          error: null,\n          ctx: opt.ctx,\n          req: {\n            url,\n            options: opt,\n            size: result.requestSize,\n          },\n          res: response,\n        });\n        if (opt.dataType === 'json') {\n          try {\n            result.data = JSON.parse(result.data);\n          } catch (err) {\n            err.name = 'JSONResponseFormatError';\n            throw err;\n          }\n        } else if (opt.dataType === 'text') {\n          result.data = result.data.toString();\n        }\n        return result;\n      }\n      return rawRequest.call(httpclient, url, opt);\n    }\n  };\n};\n"
  },
  {
    "path": "lib/parallel/agent.js",
    "content": "const debug = require('util').debuglog('egg-mock:lib:parallel:agent');\nconst path = require('path');\nconst Base = require('sdk-base');\nconst { detectPort } = require('detect-port');\nconst context = require('../context');\nconst formatOptions = require('../format_options');\nconst { sleep, rimraf } = require('../utils');\nconst mockCustomLoader = require('../mock_custom_loader');\nconst {\n  APP_INIT,\n  INIT_ONCE_LISTENER,\n  INIT_ON_LISTENER,\n  BIND_EVENT,\n  consoleLogger,\n} = require('./util');\n\nclass MockAgent extends Base {\n  constructor(options) {\n    super({ initMethod: '_init' });\n    this.options = options;\n    this.baseDir = options.baseDir;\n    this.closed = false;\n    this[APP_INIT] = false;\n    this[INIT_ON_LISTENER] = new Set();\n    this[INIT_ONCE_LISTENER] = new Set();\n    // listen once, otherwise will throw exception when emit error without listenr\n    this.once('error', err => {\n      consoleLogger.error(err);\n    });\n  }\n\n  async _init() {\n    if (this.options.beforeInit) {\n      await this.options.beforeInit(this);\n      delete this.options.beforeInit;\n    }\n    if (this.options.clean !== false) {\n      const logDir = path.join(this.options.baseDir, 'logs');\n      try {\n        await rimraf(logDir);\n      } catch (err) {\n        /* istanbul ignore next */\n        console.error(`remove log dir ${logDir} failed: ${err.stack}`);\n      }\n    }\n\n    this.options.clusterPort = process.env.CLUSTER_PORT = await detectPort();\n    debug('get clusterPort %s', this.options.clusterPort);\n    const { Agent } = require(this.options.framework);\n\n    const agent = this._instance = new Agent(Object.assign({}, this.options));\n\n    // egg-mock plugin need to override egg context\n    Object.assign(agent.context, context);\n    mockCustomLoader(agent);\n\n    debug('agent instantiate');\n    this[APP_INIT] = true;\n    debug('this[APP_INIT] = true');\n    this[BIND_EVENT]();\n    await agent.ready();\n\n    const msg = {\n      action: 'egg-ready',\n      data: this.options,\n    };\n    agent.messenger._onMessage(msg);\n    debug('agent ready');\n  }\n\n  [BIND_EVENT]() {\n    for (const args of this[INIT_ON_LISTENER]) {\n      debug('on(%s), use cache and pass to app', args);\n      this._instance.on(...args);\n      this.removeListener(...args);\n    }\n    for (const args of this[INIT_ONCE_LISTENER]) {\n      debug('once(%s), use cache and pass to app', args);\n      this._instance.on(...args);\n      this.removeListener(...args);\n    }\n  }\n\n  on(...args) {\n    if (this[APP_INIT]) {\n      debug('on(%s), pass to app', args);\n      this._instance.on(...args);\n    } else {\n      debug('on(%s), cache it because app has not init', args);\n      if (this[INIT_ON_LISTENER]) {\n        this[INIT_ON_LISTENER].add(args);\n      }\n      super.on(...args);\n    }\n  }\n\n  once(...args) {\n    if (this[APP_INIT]) {\n      debug('once(%s), pass to app', args);\n      this._instance.once(...args);\n    } else {\n      debug('once(%s), cache it because app has not init', args);\n      if (this[INIT_ONCE_LISTENER]) {\n        this[INIT_ONCE_LISTENER].add(args);\n      }\n      super.on(...args);\n    }\n  }\n\n  /**\n   * close app\n   * @return {Promise} promise\n   */\n  async close() {\n    this.closed = true;\n    const self = this;\n    if (self._instance) {\n      await self._instance.close();\n    } else {\n      // when app init throws an exception, must wait for app quit gracefully\n      await sleep(200);\n    }\n  }\n}\n\nmodule.exports = function(options) {\n  options = formatOptions(options);\n\n  return new MockAgent(options);\n};\n"
  },
  {
    "path": "lib/parallel/agent_register.js",
    "content": "console.warn('[deprecated] use `egg-mock/register.js` instead of `egg-mock/lib/parallel/agent_register.js`');\n\nmodule.exports = require('../../register');\n"
  },
  {
    "path": "lib/parallel/app.js",
    "content": "const debug = require('util').debuglog('egg-mock:lib:parallel:app');\nconst Base = require('sdk-base');\nconst context = require('../context');\nconst formatOptions = require('../format_options');\nconst { sleep } = require('../utils');\nconst mockCustomLoader = require('../mock_custom_loader');\nconst mockHttpServer = require('../mock_http_server');\nconst {\n  proxyApp,\n  APP_INIT,\n  INIT_ONCE_LISTENER,\n  INIT_ON_LISTENER,\n  BIND_EVENT,\n  consoleLogger,\n} = require('./util');\n\nclass MockApplication extends Base {\n  constructor(options) {\n    super({ initMethod: '_init' });\n    this.options = options;\n    this.baseDir = options.baseDir;\n    this.closed = false;\n    this[APP_INIT] = false;\n    this[INIT_ON_LISTENER] = new Set();\n    this[INIT_ONCE_LISTENER] = new Set();\n    // listen once, otherwise will throw exception when emit error without listenr\n    this.once('error', err => {\n      consoleLogger.error(err);\n    });\n  }\n\n  async _init() {\n    if (this.options.beforeInit) {\n      await this.options.beforeInit(this);\n      delete this.options.beforeInit;\n    }\n\n    this.options.clusterPort = this.options.clusterPort || process.env.CLUSTER_PORT;\n    if (!this.options.clusterPort) {\n      throw new Error('cannot get env.CLUSTER_PORT, parallel run fail');\n    }\n    debug('get clusterPort %s', this.options.clusterPort);\n    const { Application } = require(this.options.framework);\n\n    const app = this._instance = new Application(Object.assign({}, this.options));\n\n    // egg-mock plugin need to override egg context\n    Object.assign(app.context, context);\n    mockCustomLoader(app);\n\n    debug('app instantiate');\n    this[APP_INIT] = true;\n    debug('this[APP_INIT] = true');\n    this[BIND_EVENT]();\n    debug('http server instantiate');\n    mockHttpServer(app);\n    await app.ready();\n\n    const msg = {\n      action: 'egg-ready',\n      data: this.options,\n    };\n    app.messenger._onMessage(msg);\n    debug('app ready');\n  }\n\n  [BIND_EVENT]() {\n    for (const args of this[INIT_ON_LISTENER]) {\n      debug('on(%s), use cache and pass to app', args);\n      this._instance.on(...args);\n      this.removeListener(...args);\n    }\n    for (const args of this[INIT_ONCE_LISTENER]) {\n      debug('once(%s), use cache and pass to app', args);\n      this._instance.on(...args);\n      this.removeListener(...args);\n    }\n  }\n\n  on(...args) {\n    if (this[APP_INIT]) {\n      debug('on(%s), pass to app', args);\n      this._instance.on(...args);\n    } else {\n      debug('on(%s), cache it because app has not init', args);\n      if (this[INIT_ON_LISTENER]) {\n        this[INIT_ON_LISTENER].add(args);\n      }\n      super.on(...args);\n    }\n  }\n\n  once(...args) {\n    if (this[APP_INIT]) {\n      debug('once(%s), pass to app', args);\n      this._instance.once(...args);\n    } else {\n      debug('once(%s), cache it because app has not init', args);\n      if (this[INIT_ONCE_LISTENER]) {\n        this[INIT_ONCE_LISTENER].add(args);\n      }\n      super.on(...args);\n    }\n  }\n\n  /**\n   * close app\n   * @return {Promise} promise\n   */\n  async close() {\n    this.closed = true;\n    const self = this;\n    if (self._instance) {\n      await self._instance.close();\n    } else {\n      // when app init throws an exception, must wait for app quit gracefully\n      await sleep(200);\n    }\n  }\n}\n\nmodule.exports = function(options) {\n  options = formatOptions(options);\n\n  const app = new MockApplication(options);\n  return proxyApp(app, options);\n};\n"
  },
  {
    "path": "lib/parallel/util.js",
    "content": "const debug = require('util').debuglog('egg-mock:lib:parallel:util');\nconst ConsoleLogger = require('egg-logger').EggConsoleLogger;\nconst { getProperty } = require('../utils');\n\nconst consoleLogger = new ConsoleLogger({ level: 'INFO' });\nconst MOCK_APP_METHOD = [\n  'ready',\n  'closed',\n  'close',\n  'on',\n  'once',\n];\n\nconst INIT = Symbol('init');\nconst APP_INIT = Symbol('appInit');\nconst BIND_EVENT = Symbol('bindEvent');\nconst INIT_ON_LISTENER = Symbol('initOnListener');\nconst INIT_ONCE_LISTENER = Symbol('initOnceListener');\n\nfunction proxyApp(app) {\n  const proxyApp = new Proxy(app, {\n    get(target, prop) {\n      // don't delegate properties on MockAgent\n      if (MOCK_APP_METHOD.includes(prop)) return getProperty(target, prop);\n      if (!target[APP_INIT]) throw new Error(`can't get ${prop} before ready`);\n      // it's asyncrounus when agent and app are loading,\n      // so should get the properties after loader ready\n      debug('proxy handler.get %s', prop);\n      return target._instance[prop];\n    },\n    set(target, prop, value) {\n      if (MOCK_APP_METHOD.includes(prop)) return true;\n      if (!target[APP_INIT]) throw new Error(`can't set ${prop} before ready`);\n      debug('proxy handler.set %s', prop);\n      target._instance[prop] = value;\n      return true;\n    },\n    defineProperty(target, prop, descriptor) {\n      // can't define properties on MockAgent\n      if (MOCK_APP_METHOD.includes(prop)) return true;\n      if (!target[APP_INIT]) throw new Error(`can't defineProperty ${prop} before ready`);\n      debug('proxy handler.defineProperty %s', prop);\n      Object.defineProperty(target._instance, prop, descriptor);\n      return true;\n    },\n    deleteProperty(target, prop) {\n      // can't delete properties on MockAgent\n      if (MOCK_APP_METHOD.includes(prop)) return true;\n      if (!target[APP_INIT]) throw new Error(`can't delete ${prop} before ready`);\n      debug('proxy handler.deleteProperty %s', prop);\n      delete target._instance[prop];\n      return true;\n    },\n    getOwnPropertyDescriptor(target, prop) {\n      if (MOCK_APP_METHOD.includes(prop)) return Object.getOwnPropertyDescriptor(target, prop);\n      if (!target[APP_INIT]) throw new Error(`can't getOwnPropertyDescriptor ${prop} before ready`);\n      debug('proxy handler.getOwnPropertyDescriptor %s', prop);\n      return Object.getOwnPropertyDescriptor(target._instance, prop);\n    },\n    getPrototypeOf(target) {\n      if (!target[APP_INIT]) throw new Error('can\\'t getPrototypeOf before ready');\n      debug('proxy handler.getPrototypeOf %s');\n      return Object.getPrototypeOf(target._instance);\n    },\n  });\n  return proxyApp;\n}\n\nmodule.exports = {\n  MOCK_APP_METHOD,\n  INIT,\n  APP_INIT,\n  BIND_EVENT,\n  INIT_ON_LISTENER,\n  INIT_ONCE_LISTENER,\n  proxyApp,\n  consoleLogger,\n};\n"
  },
  {
    "path": "lib/prerequire.js",
    "content": "const debug = require('util').debuglog('egg-mock:prerequire');\nconst path = require('path');\nconst { existsSync } = require('fs');\nconst globby = require('globby');\n\nconst cwd = process.cwd();\nconst dirs = [];\nif (existsSync(path.join(cwd, 'app'))) {\n  dirs.push('app/**/*.js');\n}\n// avoid Error: ENOENT: no such file or directory, scandir\nif (existsSync(path.join(cwd, 'config'))) {\n  dirs.push('config/**/*.js');\n}\nconst files = globby.sync(dirs, { cwd });\n\nfor (const file of files) {\n  const filepath = path.join(cwd, file);\n  try {\n    debug('%s prerequire %s', process.pid, filepath);\n    require(filepath);\n  } catch (err) {\n    debug('prerequire error %s', err.message);\n  }\n}\n"
  },
  {
    "path": "lib/request_call_function.js",
    "content": "const httpclient = require('urllib');\n\nconst { port, method, args, property, needResult } = JSON.parse(process.argv[2]);\nconst url = `http://127.0.0.1:${port}/__egg_mock_call_function`;\n\nhttpclient.request(url, {\n  method: 'POST',\n  data: {\n    method,\n    args,\n    property,\n    needResult,\n  },\n  contentType: 'json',\n  dataType: 'json',\n}).then(({ data }) => {\n  if (!data.success) {\n    console.error('POST %s error, method: %s, args: %j', url, method, args);\n    if (data.error) {\n      console.error(data.error);\n    } else if (data.message) {\n      const err = new Error(data.message);\n      err.stack = data.stack;\n      console.error(err);\n    }\n    process.exit(2);\n  }\n\n  if (data.result) {\n    console.log('%j', data.result);\n  }\n  process.exit(0);\n}).catch(err => {\n  // ignore ECONNREFUSED error on mockRestore\n  if (method === 'mockRestore' && err.message.includes('ECONNREFUSED')) {\n    process.exit(0);\n  }\n\n  console.error('POST %s error, method: %s, args: %j', url, method, args);\n  console.error(err.stack);\n\n  // ignore all error on mockRestore\n  if (method === 'mockRestore') {\n    process.exit(0);\n  } else {\n    process.exit(1);\n  }\n});\n"
  },
  {
    "path": "lib/start-cluster",
    "content": "#!/usr/bin/env node\n\nif (process.env.EGG_BIN_PREREQUIRE) require('./prerequire');\n\nconst options = JSON.parse(process.argv.slice(2));\nrequire(options.framework).startCluster(options);\n"
  },
  {
    "path": "lib/supertest.js",
    "content": "'use strict';\n\nconst methods = require('methods');\nconst EggTest = require('./http_test');\nconst mockHttpServer = require('./mock_http_server');\nconst pkg = require('../package.json');\n\n// patch from https://github.com/visionmedia/supertest/blob/199506d8dbfe0bb1434fc07c38cdcd1ab4c7c926/index.js#L19\n\n/**\n * Test against the given `app`,\n * returning a new `Test`.\n *\n * @param {Application} app\n * @return {Test}\n * @public\n */\n\nmodule.exports = app => {\n  const server = mockHttpServer(app);\n  const obj = {};\n  for (const method of methods) {\n    obj[method] = url => {\n      // support pathFor(url)\n      if (url[0] !== '/') {\n        const realUrl = app.router.pathFor(url);\n        if (!realUrl) throw new Error(`Can\\'t find router:${url}, please check your \\'app/router.js\\'`);\n        url = realUrl;\n      }\n\n      const eggTest = new EggTest(server, method, url);\n      eggTest.set('user-agent', `egg-mock/${pkg.version}`);\n      return eggTest;\n    };\n  }\n  obj.del = obj.delete;\n  return obj;\n};\n"
  },
  {
    "path": "lib/tmp/.gitkeep",
    "content": ""
  },
  {
    "path": "lib/utils.js",
    "content": "const util = require('util');\nconst { rm } = require('fs/promises');\nconst { rmSync } = require('fs');\nconst is = require('is-type-of');\n\nconst setTimeoutPromise = util.promisify(setTimeout);\n\nmodule.exports = {\n  async sleep(delay) {\n    await setTimeoutPromise(delay);\n  },\n\n  async rimraf(filepath) {\n    await rm(filepath, { force: true, recursive: true });\n  },\n\n  rimrafSync(filepath) {\n    rmSync(filepath, { force: true, recursive: true });\n  },\n\n  getProperty(target, prop) {\n    const member = target[prop];\n    if (is.function(member)) {\n      return member.bind(target);\n    }\n    return member;\n  },\n  getEggOptions() {\n    const options = {};\n\n    if (process.env.EGG_BASE_DIR) {\n      options.baseDir = process.env.EGG_BASE_DIR;\n    } else {\n      options.baseDir = process.cwd();\n    }\n    if (process.env.EGG_FRAMEWORK) {\n      options.framework = process.env.EGG_FRAMEWORK;\n    }\n    return options;\n  },\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"egg-mock\",\n  \"version\": \"5.15.2\",\n  \"eggPlugin\": {\n    \"name\": \"egg-mock\"\n  },\n  \"description\": \"mock server for egg\",\n  \"types\": \"index.d.ts\",\n  \"main\": \"index.js\",\n  \"files\": [\n    \"app.js\",\n    \"index.js\",\n    \"index.d.ts\",\n    \"bootstrap.js\",\n    \"bootstrap.d.ts\",\n    \"app\",\n    \"lib\",\n    \"register.js\"\n  ],\n  \"scripts\": {\n    \"lint\": \"eslint lib app index.js test/*.test.js\",\n    \"tsd\": \"tsd\",\n    \"test\": \"npm run lint && npm run tsd && npm run test-local\",\n    \"test-local\": \"egg-bin test -r ./register.js --ts false\",\n    \"cov\": \"egg-bin cov -r ./register.js --ts false\",\n    \"ci\": \"npm run lint && npm run tsd && npm run cov\"\n  },\n  \"dependencies\": {\n    \"@eggjs/utils\": \"^4.0.2\",\n    \"@types/supertest\": \"^2.0.7\",\n    \"await-event\": \"^2.1.0\",\n    \"co\": \"^4.6.0\",\n    \"coffee\": \"^5.2.1\",\n    \"detect-port\": \"^2.0.1\",\n    \"egg-logger\": \"^3.5.0\",\n    \"extend2\": \"^1.0.0\",\n    \"get-ready\": \"^3.1.0\",\n    \"globby\": \"^11.1.0\",\n    \"is-type-of\": \"^2.2.0\",\n    \"merge-descriptors\": \"^1.0.1\",\n    \"methods\": \"^1.1.2\",\n    \"mm\": \"^3.0.2\",\n    \"sdk-base\": \"^4.2.1\",\n    \"supertest\": \"^6.2.4\",\n    \"urllib\": \"3\"\n  },\n  \"peerDependencies\": {\n    \"egg\": \"^3.12.0\",\n    \"mocha\": \"^10.2.0\",\n    \"urllib\": \"^3 || ^4\"\n  },\n  \"devDependencies\": {\n    \"@eggjs/tegg\": \"^3.2.2\",\n    \"@eggjs/tegg-config\": \"^3.2.2\",\n    \"@eggjs/tegg-controller-plugin\": \"^3.2.2\",\n    \"@eggjs/tegg-plugin\": \"^3.2.2\",\n    \"@eggjs/tsconfig\": \"^1.1.0\",\n    \"@types/mocha\": \"^10.0.1\",\n    \"@types/node\": \"20\",\n    \"egg\": \"^3.12.0\",\n    \"egg-bin\": \"^6.0.0\",\n    \"egg-errors\": \"^2.2.1\",\n    \"egg-tracer\": \"^2.0.0\",\n    \"eslint\": \"^8.24.0\",\n    \"eslint-config-egg\": \"^12.0.0\",\n    \"mocha\": \"^10.1.0\",\n    \"pedding\": \"^1.1.0\",\n    \"tsd\": \"^0.31.0\",\n    \"typescript\": \"5\"\n  },\n  \"homepage\": \"https://github.com/eggjs/egg-mock\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/eggjs/egg-mock.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/eggjs/egg/issues\"\n  },\n  \"keywords\": [\n    \"egg\",\n    \"mock\"\n  ],\n  \"engines\": {\n    \"node\": \">= 14.18.0\"\n  },\n  \"author\": \"popomore <sakura9515@gmail.com>\"\n}\n"
  },
  {
    "path": "register.js",
    "content": "const debug = require('util').debuglog('egg-mock:register');\nconst mock = require('./index').default;\nconst agentHandler = require('./lib/agent_handler');\nconst appHandler = require('./lib/app_handler');\nconst injectContext = require('./lib/inject_context');\n\nexports.mochaGlobalSetup = async () => {\n  debug('mochaGlobalSetup, agent.setupAgent() start');\n  await agentHandler.setupAgent();\n  debug('mochaGlobalSetup, agent.setupAgent() end');\n};\n\nexports.mochaGlobalTeardown = async () => {\n  debug('mochaGlobalTeardown, agent.closeAgent() start');\n  await agentHandler.closeAgent();\n  debug('mochaGlobalTeardown, agent.closeAgent() end');\n};\n\nexports.mochaHooks = {\n  async beforeAll() {\n    const app = await appHandler.getApp();\n    debug('mochaHooks.beforeAll call, _app: %s', app);\n    if (app) {\n      await app.ready();\n    }\n  },\n  async afterEach() {\n    const app = await appHandler.getApp();\n    debug('mochaHooks.afterEach call, _app: %s', app);\n    if (app) {\n      await app.backgroundTasksFinished();\n    }\n    await mock.restore();\n  },\n  async afterAll() {\n    // skip auto app close on parallel\n    if (process.env.ENABLE_MOCHA_PARALLEL) return;\n    const app = await appHandler.getApp();\n    debug('mochaHooks.afterAll call, _app: %s', app);\n    if (app) {\n      await app.close();\n    }\n  },\n};\n\n/**\n * Find active node mocha instances.\n *\n * @return {Array}\n */\nfunction findNodeJSMocha() {\n  const children = require.cache || {};\n\n  return Object.keys(children)\n    .filter(function(child) {\n      const val = children[child].exports;\n      return typeof val === 'function' && val.name === 'Mocha';\n    })\n    .map(function(child) {\n      return children[child].exports;\n    });\n}\n\nrequire('mocha');\nconst modules = findNodeJSMocha();\n\nfor (const module of modules) {\n  injectContext(module);\n}\n\n"
  },
  {
    "path": "test/agent.test.js",
    "content": "'use strict';\n\nconst mm = require('..');\nconst fs = require('fs');\nconst path = require('path');\nconst { rimraf } = require('../lib/utils');\nconst assert = require('assert');\n\nconst fixtures = path.join(__dirname, 'fixtures');\nconst baseDir = path.join(fixtures, 'agent');\n\ndescribe('test/agent.test.js', () => {\n  let app;\n  afterEach(() => app.close());\n  afterEach(mm.restore);\n\n  it('mock agent ok', async () => {\n    const filepath = path.join(baseDir, 'run/test.txt');\n    await rimraf(filepath);\n\n    app = mm.app({\n      baseDir,\n    });\n\n    await app.ready();\n    assert(fs.readFileSync(filepath, 'utf8') === '123');\n  });\n\n  it('mock agent again ok', done => {\n    app = mm.app({\n      baseDir,\n    });\n    app.ready(done);\n  });\n\n  it('should cluster-client work', done => {\n    app = mm.app({ baseDir });\n    app.ready(() => {\n      app._agent.client.subscribe('agent sub', data => {\n        assert(data === 'agent sub');\n\n        app.client.subscribe('app sub', data => {\n          assert(data === 'app sub');\n          done();\n        });\n      });\n    });\n  });\n\n  it('should agent work ok after ready', function* () {\n    app = mm.app({ baseDir });\n    yield app.ready();\n    assert(app._agent.type === 'agent');\n  });\n\n  it('should FrameworkErrorformater work during agent boot', function* () {\n    let logMsg;\n    let catchErr;\n    mm(process.stderr, 'write', msg => {\n      logMsg = msg;\n    });\n    app = mm.app({ baseDir: path.join(fixtures, 'agent-boot-error') });\n    try {\n      yield app.ready();\n    } catch (err) {\n      catchErr = err;\n    }\n\n    assert(catchErr.code === 'customPlugin_99');\n    assert(/framework\\.CustomError\\: mock error \\[ https\\:\\/\\/eggjs\\.org\\/zh-cn\\/faq\\/customPlugin_99 \\]/.test(logMsg));\n  });\n\n  it('should FrameworkErrorformater work during agent boot ready', function* () {\n    let logMsg;\n    let catchErr;\n    mm(process.stderr, 'write', msg => {\n      logMsg = msg;\n    });\n    app = mm.app({ baseDir: path.join(fixtures, 'agent-boot-ready-error') });\n    try {\n      yield app.ready();\n    } catch (err) {\n      catchErr = err;\n    }\n\n    assert(catchErr.code === 'customPlugin_99');\n    assert(/framework\\.CustomError\\: mock error \\[ https\\:\\/\\/eggjs\\.org\\/zh-cn\\/faq\\/customPlugin_99 \\]/.test(logMsg));\n  });\n});\n"
  },
  {
    "path": "test/app/middleware/cluster_app_mock.test.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst mm = require('../../..');\n\ndescribe('test/app/middleware/cluster_app_mock.test.js', () => {\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: 'demo',\n    });\n    return app.ready();\n  });\n  after(() => app.close());\n\n  afterEach(mm.restore);\n\n  it('should return 422 when method missing', () => {\n    return app.httpRequest()\n      .post('/__egg_mock_call_function')\n      .send({})\n      .expect(422)\n      .expect({\n        success: false,\n        error: 'Missing method',\n      });\n  });\n\n  it('should return 422 when args is not Array', () => {\n    return app.httpRequest()\n      .post('/__egg_mock_call_function')\n      .send({ method: 'foo', args: 'hi' })\n      .expect(422)\n      .expect({\n        success: false,\n        error: 'args should be an Array instance',\n      });\n  });\n\n  it('should return 422 when method is not exists on app', () => {\n    return app.httpRequest()\n      .post('/__egg_mock_call_function')\n      .send({ method: 'not_exists_method', args: [] })\n      .expect(422)\n      .expect({\n        success: false,\n        error: 'method \"not_exists_method\" not exists on app',\n      });\n  });\n\n  it('should recover error instance', function* () {\n    let called;\n    let callError;\n    mm(app, 'foo', (a, err) => { called = true; callError = err; });\n\n    const err = {\n      __egg_mock_type: 'error',\n      name: 'FooError',\n      message: 'foo error fire',\n      stack: 'error stack',\n      foo: 'bar',\n    };\n    yield app.httpRequest()\n      .post('/__egg_mock_call_function')\n      .send({ method: 'foo', args: [ 1, err ] })\n      .expect(200)\n      .expect({\n        success: true,\n      });\n\n    assert(called);\n    assert(callError.name === 'FooError');\n    assert(callError.stack === 'error stack');\n    assert(callError.message === 'foo error fire');\n    assert(callError.foo === 'bar');\n  });\n});\n"
  },
  {
    "path": "test/app.test.js",
    "content": "'use strict';\n\nconst request = require('supertest');\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\n\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/app.test.js', () => {\n  afterEach(mm.restore);\n\n  // test mm.app\n  call('app');\n  // test mm.cluster\n  call('cluster');\n\n  it('should alias app.agent to app._agent', async () => {\n    const baseDir = path.join(fixtures, 'app');\n    const app = mm.app({\n      baseDir,\n      customEgg: path.join(__dirname, '../node_modules/egg'),\n    });\n    await app.ready();\n    assert(app.agent === app._agent);\n    assert(app.agent.app === app._app);\n  });\n\n  it('should not use cache when app is closed', async () => {\n    const baseDir = path.join(fixtures, 'app');\n    const app1 = mm.app({\n      baseDir,\n      customEgg: path.join(__dirname, '../node_modules/egg'),\n    });\n    await app1.ready();\n    await app1.close();\n\n    const app2 = mm.app({\n      baseDir,\n      customEgg: path.join(__dirname, '../node_modules/egg'),\n    });\n    await app2.ready();\n    await app2.close();\n\n    assert(app1 !== app2);\n  });\n\n  it('should auto find framework when egg.framework exists on package.json', async () => {\n    const baseDir = path.join(fixtures, 'yadan_app');\n    const app = mm.app({\n      baseDir,\n    });\n    await app.ready();\n    assert(app.config.foobar === 'yadan');\n    await app.close();\n  });\n\n  it('should emit server event on app without superTest', async () => {\n    const baseDir = path.join(fixtures, 'server');\n    const app = mm.app({\n      baseDir,\n    });\n    await app.ready();\n    assert(app.server);\n    assert(app.emitServer);\n    await app.close();\n  });\n\n  it('support options.beforeInit', async () => {\n    const baseDir = path.join(fixtures, 'app');\n    const app = mm.app({\n      baseDir,\n      customEgg: path.join(__dirname, '../node_modules/egg'),\n      cache: false,\n      beforeInit(instance) {\n        return new Promise(resolve => {\n          setTimeout(() => {\n            instance.options.test = 'abc';\n            resolve();\n          }, 100);\n        });\n      },\n    });\n    await app.ready();\n    assert(!app.options.beforeInit);\n    assert(app.options.test === 'abc');\n  });\n\n  it('should emit error when load Application fail', done => {\n    const baseDir = path.join(fixtures, 'app-fail');\n    const app = mm.app({ baseDir, cache: false });\n    app.once('error', err => {\n      assert(/load error/.test(err.message));\n      done();\n    });\n  });\n\n  it('should FrameworkErrorformater work during app boot', async () => {\n    let logMsg;\n    let catchErr;\n    mm(process.stderr, 'write', msg => {\n      logMsg = msg;\n    });\n    const app = mm.app({ baseDir: path.join(fixtures, 'app-boot-error') });\n    try {\n      await app.ready();\n    } catch (err) {\n      catchErr = err;\n    }\n\n    assert(catchErr.code === 'customPlugin_99');\n    assert(/framework\\.CustomError\\: mock error \\[ https\\:\\/\\/eggjs\\.org\\/zh-cn\\/faq\\/customPlugin_99 \\]/.test(logMsg));\n  });\n\n  it('should FrameworkErrorformater work during app boot ready', async () => {\n    let logMsg;\n    let catchErr;\n    mm(process.stderr, 'write', msg => {\n      logMsg = msg;\n    });\n    const app = mm.app({ baseDir: path.join(fixtures, 'app-boot-ready-error') });\n    try {\n      await app.ready();\n    } catch (err) {\n      catchErr = err;\n    }\n\n    assert(catchErr.code === 'customPlugin_99');\n    assert(/framework\\.CustomError\\: mock error \\[ https\\:\\/\\/eggjs\\.org\\/zh-cn\\/faq\\/customPlugin_99 \\]/.test(logMsg));\n  });\n});\n\nfunction call(method) {\n  let app;\n  describe(`mm.${method}()`, () => {\n    before(done => {\n      const baseDir = path.join(fixtures, 'app');\n      mm(process, 'cwd', () => baseDir);\n      app = mm[method]({\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/')\n        .expect('foo')\n        .expect(200, done);\n    });\n\n    it('should emit server event on app', () => {\n      return app.httpRequest()\n        .get('/keepAliveTimeout')\n        .expect(200)\n        .expect({\n          keepAliveTimeout: 5000,\n        });\n    });\n\n    it('should app.expectLog(), app.notExpectLog() work', async () => {\n      await app.httpRequest()\n        .get('/logger')\n        .expect(200)\n        .expect({\n          ok: true,\n        });\n      app.expectLog('[app.expectLog() test] ok');\n      app.expectLog('[app.expectLog() test] ok', 'logger');\n      app.expectLog('[app.expectLog(coreLogger) test] ok', 'coreLogger');\n\n      app.notExpectLog('[app.notExpectLog() test] fail');\n      app.notExpectLog('[app.notExpectLog() test] fail', 'logger');\n      app.notExpectLog('[app.notExpectLog(coreLogger) test] fail', 'coreLogger');\n\n      if (method === 'app') {\n        app.expectLog(/\\[app\\.expectLog\\(\\) test\\] ok/);\n        app.expectLog(/\\[app\\.expectLog\\(\\) test\\] ok/, app.logger);\n        app.expectLog('[app.expectLog(coreLogger) test] ok', app.coreLogger);\n        app.expectLog(/\\[app\\.expectLog\\(coreLogger\\) test\\] ok/, 'coreLogger');\n\n        app.notExpectLog(/\\[app\\.notExpectLog\\(\\) test\\] fail/);\n        app.notExpectLog(/\\[app\\.notExpectLog\\(\\) test\\] fail/, app.logger);\n        app.notExpectLog('[app.notExpectLog(coreLogger) test] fail', app.coreLogger);\n        app.notExpectLog(/\\[app\\.notExpectLog\\(coreLogger\\) test\\] fail/, 'coreLogger');\n      }\n\n      try {\n        app.expectLog('[app.expectLog(coreLogger) test] ok');\n        throw new Error('should not run this');\n      } catch (err) {\n        assert(err.message.includes('Can\\'t find String:\"[app.expectLog(coreLogger) test] ok\" in '));\n        assert(err.message.includes('app-web.log'));\n      }\n\n      try {\n        app.notExpectLog('[app.expectLog() test] ok');\n        throw new Error('should not run this');\n      } catch (err) {\n        assert(err.message.includes('Find String:\"[app.expectLog() test] ok\" in '));\n        assert(err.message.includes('app-web.log'));\n      }\n    });\n\n    it('should app.mockLog() then app.expectLog() work', async () => {\n      app.mockLog();\n      app.mockLog('logger');\n      app.mockLog('coreLogger');\n      await app.httpRequest()\n        .get('/logger')\n        .expect(200)\n        .expect({\n          ok: true,\n        });\n      app.expectLog('[app.expectLog() test] ok');\n      app.expectLog('[app.expectLog() test] ok', 'logger');\n      app.expectLog('[app.expectLog(coreLogger) test] ok', 'coreLogger');\n\n      app.notExpectLog('[app.notExpectLog() test] fail');\n      app.notExpectLog('[app.notExpectLog() test] fail', 'logger');\n      app.notExpectLog('[app.notExpectLog(coreLogger) test] fail', 'coreLogger');\n\n      if (method === 'app') {\n        app.expectLog(/\\[app\\.expectLog\\(\\) test\\] ok/);\n        app.expectLog(/\\[app\\.expectLog\\(\\) test\\] ok/, app.logger);\n        app.expectLog('[app.expectLog(coreLogger) test] ok', app.coreLogger);\n        app.expectLog(/\\[app\\.expectLog\\(coreLogger\\) test\\] ok/, 'coreLogger');\n\n        app.notExpectLog(/\\[app\\.notExpectLog\\(\\) test\\] fail/);\n        app.notExpectLog(/\\[app\\.notExpectLog\\(\\) test\\] fail/, app.logger);\n        app.notExpectLog('[app.notExpectLog(coreLogger) test] fail', app.coreLogger);\n        app.notExpectLog(/\\[app\\.notExpectLog\\(coreLogger\\) test\\] fail/, 'coreLogger');\n      }\n\n      try {\n        app.expectLog('[app.expectLog(coreLogger) test] ok');\n        throw new Error('should not run this');\n      } catch (err) {\n        assert(err.message.includes('Can\\'t find String:\"[app.expectLog(coreLogger) test] ok\" in '));\n        assert(err.message.includes('app-web.log'));\n      }\n\n      try {\n        app.notExpectLog('[app.expectLog() test] ok');\n        throw new Error('should not run this');\n      } catch (err) {\n        assert(err.message.includes('Find String:\"[app.expectLog() test] ok\" in '));\n        assert(err.message.includes('app-web.log'));\n      }\n\n      if (method === 'app') {\n        assert(app.logger._mockLogs);\n        assert(app.coreLogger._mockLogs);\n        await mm.restore();\n        assert(!app.logger._mockLogs);\n        assert(!app.coreLogger._mockLogs);\n      }\n    });\n\n    it('should app.mockLog() don\\'t read from file', async () => {\n      await app.httpRequest()\n        .get('/logger')\n        .expect(200)\n        .expect({\n          ok: true,\n        });\n      app.expectLog('INFO');\n      app.mockLog();\n      app.notExpectLog('INFO');\n    });\n\n    it('should request with ua', async () => {\n      await app.httpRequest()\n        .get('/ua')\n        .expect(200)\n        .expect(/egg-mock\\//);\n    });\n  });\n\n  describe(`mm.${method}({ baseDir, plugin=string })`, () => {\n    const pluginDir = path.join(fixtures, 'fooPlugin');\n    before(done => {\n      mm(process, 'cwd', () => pluginDir);\n      app = mm[method]({\n        baseDir: path.join(__dirname, 'fixtures/apps/foo'),\n        plugin: 'fooPlugin',\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/')\n        .expect({\n          fooPlugin: true,\n        })\n        .expect(200, done);\n    });\n  });\n\n  describe(`mm.${method}({ baseDir, plugin=true })`, () => {\n    const pluginDir = path.join(fixtures, 'fooPlugin');\n    before(done => {\n      mm(process, 'cwd', () => pluginDir);\n      app = mm[method]({\n        baseDir: path.join(__dirname, 'fixtures/apps/foo'),\n        plugin: true,\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/')\n        .expect({\n          fooPlugin: true,\n        })\n        .expect(200, done);\n    });\n  });\n\n  describe(`mm.${method}({ baseDir, plugins })`, () => {\n    before(done => {\n      app = mm[method]({\n        baseDir: path.join(__dirname, 'fixtures/apps/foo'),\n        plugins: {\n          fooPlugin: {\n            enable: true,\n            path: path.join(fixtures, 'fooPlugin'),\n          },\n        },\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/')\n        .expect({\n          fooPlugin: true,\n        })\n        .expect(200, done);\n    });\n  });\n\n  describe(`mm.${method}({ baseDir, customEgg=fullpath})`, () => {\n    before(done => {\n      app = mm[method]({\n        baseDir: 'apps/barapp',\n        customEgg: path.join(fixtures, 'bar'),\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/')\n        .expect({\n          foo: 'bar',\n          foobar: 'bar',\n        })\n        .expect(200, done);\n    });\n  });\n\n\n  describe(`mm.${method}({ baseDir, customEgg=true})`, () => {\n    before(done => {\n      mm(process, 'cwd', () => {\n        return path.join(fixtures, 'bar');\n      });\n      app = mm[method]({\n        baseDir: path.join(fixtures, 'apps/barapp'),\n        customEgg: true,\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/')\n        .expect({\n          foo: 'bar',\n          foobar: 'bar',\n        })\n        .expect(200, done);\n    });\n  });\n\n  describe(`mm.${method}({ baseDir, cache=true })`, () => {\n    let app1;\n    let app2;\n    before(done => {\n      app1 = mm[method]({\n        baseDir: 'cache',\n        coverage: false,\n      });\n      app1.ready(done);\n    });\n    before(done => {\n      app2 = mm[method]({\n        baseDir: 'cache',\n        coverage: false,\n      });\n      app2.ready(done);\n    });\n    after(async () => {\n      await app1.close();\n      await app2.close();\n    });\n\n    it('should equal', () => {\n      assert(app1 === app2);\n    });\n  });\n}\n"
  },
  {
    "path": "test/app_event.test.js",
    "content": "const path = require('path');\nconst request = require('supertest');\nconst pedding = require('pedding');\nconst assert = require('assert');\nconst mm = require('..');\nconst { sleep } = require('../lib/utils');\nconst fixtures = path.join(__dirname, 'fixtures');\nconst baseDir = path.join(fixtures, 'app-event');\n\ndescribe('test/app_event.test.js', () => {\n  afterEach(mm.restore);\n\n  describe('after ready', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should listen by eventByRequest', done => {\n      done = pedding(3, done);\n      app.once('eventByRequest', done);\n      app.on('eventByRequest', done);\n\n      request(app.callback())\n        .get('/event')\n        .expect(200)\n        .expect('done', done);\n    });\n  });\n\n  describe('before ready', () => {\n    let app;\n    beforeEach(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n    });\n    afterEach(() => app.ready());\n    afterEach(() => app.close());\n\n    it('should listen after app ready', done => {\n      done = pedding(2, done);\n      app.once('appReady', done);\n      app.on('appReady', done);\n    });\n\n    it('should listen after app instantiate', done => {\n      done = pedding(2, done);\n      app.once('appInstantiated', done);\n      app.on('appInstantiated', done);\n    });\n  });\n\n  describe('throw before app init', () => {\n    let app;\n    beforeEach(() => {\n      const baseDir = path.join(fixtures, 'app');\n      const customEgg = path.join(fixtures, 'error-framework');\n      app = mm.app({\n        baseDir,\n        customEgg,\n        cache: false,\n      });\n    });\n    afterEach(() => app.close());\n\n    it('should listen using app.on', done => {\n      app.on('error', err => {\n        assert(err.message === 'start error');\n        done();\n      });\n    });\n\n    it('should listen using app.once', done => {\n      app.once('error', err => {\n        assert(err.message === 'start error');\n        done();\n      });\n    });\n\n    it('should throw error from ready', function* () {\n      try {\n        yield app.ready();\n      } catch (err) {\n        assert(err.message === 'start error');\n      }\n    });\n\n    it('should close when app init failed', function* () {\n      app.once('error', () => {});\n      yield sleep(1000);\n      // app._app is undefined\n      yield app.close();\n    });\n\n  });\n});\n"
  },
  {
    "path": "test/app_proxy.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\nconst fixtures = path.join(__dirname, 'fixtures');\nconst baseDir = path.join(fixtures, 'app-proxy');\n\ndescribe('test/app_proxy.test.js', () => {\n  afterEach(mm.restore);\n\n  describe('when before ready', () => {\n    let app;\n    const baseDir = path.join(fixtures, 'app-proxy-ready');\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n    });\n    after(function* () {\n      yield app.ready();\n      yield app.close();\n    });\n\n    it('should not get property', function* () {\n      assert.throws(() => {\n        app.config;\n      }, /can't get config before ready/);\n    });\n\n    it('should not set property', function* () {\n      assert.throws(() => {\n        app.curl = function* mockCurl() {\n          return 'mock';\n        };\n      }, /can't set curl before ready/);\n    });\n\n    it('should not define property', function* () {\n      assert.throws(() => {\n        Object.defineProperty(app, 'config', {\n          value: {},\n        });\n      }, /can't defineProperty config before ready/);\n    });\n\n    it('should not delete property', function* () {\n      assert.throws(() => {\n        delete app.config;\n      }, /can't delete config before ready/);\n    });\n\n    it('should not getOwnPropertyDescriptor property', function* () {\n      assert.throws(() => {\n        Object.getOwnPropertyDescriptor(app, 'config');\n      }, /can't getOwnPropertyDescriptor config before ready/);\n    });\n\n    it('should not getPrototypeOf property', function* () {\n      assert.throws(() => {\n        Object.getPrototypeOf(app);\n      }, /can't getPrototypeOf before ready/);\n    });\n  });\n\n  describe('handler.get', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should get property', () => {\n      assert(app.getter === 'getter');\n      assert(app.method() === 'method');\n    });\n\n    it('should ignore when get property on MockApplication', function* () {\n      assert(app.closed === false);\n      yield app.close();\n      assert(app.closed === true);\n    });\n  });\n\n  describe('handler.set', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should override property with setter', function* () {\n      app.curl = function* mockCurl() {\n        return 'mock';\n      };\n      const data = yield app.curl();\n      assert(data === 'mock');\n    });\n\n    it('should ignore when set property on MockApplication', function* () {\n      app.closed = true;\n      assert(app.closed === false);\n      yield app.close();\n    });\n  });\n\n  describe('handler.defineProperty', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should defineProperty', function* () {\n      assert(app.prop === 1);\n      Object.defineProperty(app, 'prop', {\n        get() {\n          if (!this._prop) {\n            this._prop = 0;\n          }\n          return this._prop++;\n        },\n        set(prop) {\n          if (this._prop) {\n            this._prop = this._prop + prop;\n          }\n        },\n      });\n\n      assert(app.prop === 0);\n      assert(app.prop === 1);\n      app.prop = 2;\n      assert(app.prop === 4);\n      app.prop = 2;\n      assert(app.prop === 7);\n    });\n\n    it('should ignore when defineProperty on MockApplication', function* () {\n      assert(app.closed === false);\n      Object.defineProperty(app, 'closed', {\n        value: true,\n      });\n      assert(app.closed === false);\n      assert(!app._app.closed);\n    });\n  });\n\n  describe('handler.deleteProperty', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should delete property', () => {\n      assert(app.shouldBeDelete === true);\n      delete app.shouldBeDelete;\n      assert(app.shouldBeDelete === undefined);\n    });\n\n    it('should ignore when delete property on MockApplication', function* () {\n      assert(!app._app.closed);\n      assert(app.closed === false);\n      delete app.closed;\n      assert(!app._app.closed);\n      assert(app.closed === false);\n    });\n  });\n\n  describe('handler.getOwnPropertyDescriptor', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should getOwnPropertyDescriptor', () => {\n      const d = Object.getOwnPropertyDescriptor(app, 'a');\n      assert(typeof d.get === 'function');\n      assert(typeof d.set === 'function');\n    });\n\n    it('should ignore when getOwnPropertyDescriptor on MockApplication', function* () {\n      const d = Object.getOwnPropertyDescriptor(app, 'closed');\n      assert(d.value === false);\n    });\n  });\n\n  describe('handler.getPrototypeOf', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should getPrototypeOf', () => {\n      assert(Object.getPrototypeOf(app) === Object.getPrototypeOf(app._app));\n    });\n  });\n\n  describe('MOCK_APP_METHOD', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should be used on MockApplication', () => {\n      const MOCK_APP_METHOD = [\n        'ready',\n        'closed',\n        'close',\n        '_agent',\n        '_app',\n        'on',\n        'once',\n      ];\n      for (const key of MOCK_APP_METHOD) {\n        assert(app[key] !== app._app[key]);\n      }\n    });\n  });\n\n  describe('messenger binding', () => {\n    let app;\n    const baseDir = path.join(fixtures, 'messenger-binding');\n    before(() => {\n      app = mm.app({\n        baseDir,\n        cache: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should send message from app to agent', () => {\n      assert.deepEqual(app._agent.received, [\n        'send data when app starting',\n        'send data when app started',\n        'send data to a random agent',\n      ]);\n    });\n\n    it('should send message from agent to app', () => {\n      process.nextTick(() => {\n        assert.deepEqual(app._app.received, [\n          'send data when server started',\n          'send data to a random app',\n        ]);\n      });\n    });\n\n    it('should receive egg-ready', () => {\n      assert(app._app.eggReady === true);\n      assert(app._agent.eggReady === true);\n      assert(app._agent.eggReadyData.baseDir === baseDir);\n      assert(app._app.eggReadyData.baseDir === baseDir);\n    });\n\n    it('should broadcast message successfully', () => {\n      assert(app._app.recievedBroadcastAction === true);\n      assert(app._agent.recievedBroadcastAction === true);\n      assert(app._app.recievedAgentRecievedAction === true);\n    });\n\n    it('should send message from app to app', () => {\n      assert(app._app.recievedAppAction === true);\n    });\n\n  });\n});\n"
  },
  {
    "path": "test/bootstrap-plugin.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst coffee = require('coffee');\nconst mock = require('mm');\n\ndescribe('test/bootstrap-plugin.test.js', () => {\n\n  after(() => mock.restore());\n\n  it('should throw', () => {\n    mock(process.env, 'EGG_BASE_DIR', path.join(__dirname, './fixtures/plugin-bootstrap'));\n\n    const testFile = path.join(__dirname, './fixtures/plugin-bootstrap/test.js');\n\n    return coffee.fork(testFile)\n      // .debug()\n      .expect('stderr', /DO NOT USE bootstrap to test plugin/)\n      .expect('code', 1)\n      .end();\n  });\n});\n"
  },
  {
    "path": "test/bootstrap.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst baseDir = process.env.EGG_BASE_DIR = path.join(__dirname, './fixtures/app');\nconst { app, assert, mm, mock } = require('../bootstrap');\n\ndescribe('test/bootstrap.test.js', () => {\n  it('should create app success', () => {\n    assert(app.baseDir === baseDir);\n  });\n\n  it('should mock and mm success', () => {\n    assert(app.baseDir === baseDir);\n    mm(app, 'baseDir', 'foo');\n    assert(app.baseDir === 'foo');\n    mock(app, 'baseDir', 'bar');\n    assert(app.baseDir === 'bar');\n  });\n\n  it('should afterEach(mm.restore) success', () => {\n    assert(app.baseDir === baseDir);\n  });\n\n  it('should assert success', done => {\n    try {\n      assert(app.baseDir !== baseDir);\n    } catch (err) {\n      done();\n    }\n  });\n\n  describe('backgroundTasksFinished()', () => {\n    it('should wait for background task 1 finished', function* () {\n      yield app.httpRequest()\n        .get('/counter')\n        .expect(200)\n        .expect({ counter: 0 });\n      yield app.httpRequest()\n        .get('/counter/plus')\n        .expect(200)\n        .expect({ counter: 0 });\n    });\n\n    it('should wait for background task 2 finished', function* () {\n      yield app.httpRequest()\n        .get('/counter')\n        .expect(200)\n        .expect({ counter: 1 });\n      yield app.httpRequest()\n        .get('/counter/minus')\n        .expect(200)\n        .expect({ counter: 1 });\n    });\n\n    it('should wait for background task 3 finished', function* () {\n      yield app.httpRequest()\n        .get('/counter')\n        .expect(200)\n        .expect({ counter: 0 });\n      app.mockContext({ superMan: true });\n      yield app.httpRequest()\n        .get('/counter/plus')\n        .expect(200)\n        .expect({ counter: 0 });\n    });\n\n    it('should wait for background task 4 finished', function* () {\n      yield app.httpRequest()\n        .get('/counter')\n        .expect(200)\n        .expect({ counter: 10 });\n      yield app.httpRequest()\n        .get('/counter/plusplus')\n        .expect(200)\n        .expect({ counter: 10 });\n    });\n\n    it('should wait for background task 5 finished', function* () {\n      yield app.httpRequest()\n        .get('/counter')\n        .expect(200)\n        .expect({ counter: 12 });\n      app.mockContext({ superMan: true });\n      yield app.httpRequest()\n        .get('/counter/plusplus')\n        .expect(200)\n        .expect({ counter: 12 });\n    });\n\n    it('should all reset', function* () {\n      yield app.httpRequest()\n        .get('/counter')\n        .expect(200)\n        .expect({ counter: 32 });\n    });\n\n    it('should always return promise instance', () => {\n      let p = app.backgroundTasksFinished();\n      assert(p.then);\n      p = app.backgroundTasksFinished();\n      assert(p.then);\n      p = app.backgroundTasksFinished();\n      assert(p.then);\n    });\n  });\n});\n"
  },
  {
    "path": "test/cluster.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst request = require('supertest');\nconst mm = require('..');\n\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/cluster.test.js', () => {\n\n  afterEach(mm.restore);\n\n  describe('normal', () => {\n    let app;\n    before(() => {\n      app = mm.cluster({\n        baseDir: path.join(fixtures, 'demo'),\n        cache: false,\n        coverage: false,\n      });\n      // app.debug();\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should have members', async () => {\n      assert(app.callback() === app);\n      assert(app.listen() === app);\n      await app.ready();\n      assert(app.process);\n    });\n\n    it('should throw error when mock function not exists', () => {\n      assert.throws(() => {\n        app.mockNotExists();\n      }, /method \"mockNotExists\" not exists on app/);\n    });\n\n    it('should listen on port', () => {\n      app.expect('stdout', /egg started on http:\\/\\/127.0.0.1:17\\d{3}/);\n    });\n  });\n\n  describe('cluster with fullpath baseDir', () => {\n    let app;\n    before(done => {\n      app = mm.cluster({\n        baseDir: path.join(fixtures, 'demo'),\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/hello')\n        .expect('hi')\n        .expect(200, done);\n    });\n  });\n\n  describe('cluster with shortpath baseDir', () => {\n    let app;\n    before(done => {\n      app = mm.cluster({\n        baseDir: 'demo',\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/hello')\n        .expect('hi')\n        .expect(200, done);\n    });\n  });\n\n  describe('cluster with customEgg=string', () => {\n    let app;\n    before(done => {\n      app = mm.cluster({\n        baseDir: 'apps/barapp',\n        customEgg: path.join(fixtures, 'bar'),\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/')\n        .expect({\n          foo: 'bar',\n          foobar: 'bar',\n        })\n        .expect(200, done);\n    });\n  });\n\n  describe('cluster with customEgg=true', () => {\n    let app;\n    before(done => {\n      mm(process, 'cwd', () => {\n        return path.join(fixtures, 'bar');\n      });\n      app = mm.cluster({\n        baseDir: path.join(fixtures, 'apps/barapp'),\n        customEgg: true,\n        cache: false,\n        coverage: false,\n      });\n      app.ready(done);\n    });\n    after(() => app.close());\n\n    it('should work', done => {\n      request(app.callback())\n        .get('/')\n        .expect({\n          foo: 'bar',\n          foobar: 'bar',\n        })\n        .expect(200, done);\n    });\n  });\n\n  describe('cluster with cache', () => {\n    let app1;\n    let app2;\n    afterEach(() => {\n      const promises = [];\n      app1 && promises.push(app1.close());\n      app2 && promises.push(app2.close());\n      return Promise.all(promises);\n    });\n\n    it('should return cached cluster app', async () => {\n      app1 = mm.cluster({\n        baseDir: 'demo',\n        coverage: false,\n      });\n      await app1.ready();\n\n      app2 = mm.cluster({\n        baseDir: 'demo',\n        coverage: false,\n      });\n      await app2.ready();\n\n      assert(app1 === app2);\n    });\n\n    it('should return new app if cached app has been closed', async () => {\n      app1 = mm.cluster({\n        baseDir: 'demo',\n        coverage: false,\n      });\n      await app1.ready();\n      await app1.close();\n\n      app2 = mm.cluster({\n        baseDir: 'demo',\n        coverage: false,\n      });\n      await app2.ready();\n\n      assert(app2 !== app1);\n    });\n\n  });\n\n  describe('cluster with eggPath', () => {\n    let app;\n    after(() => app.close());\n\n    it('should get eggPath', async () => {\n      app = mm.cluster({\n        baseDir: 'demo',\n        customEgg: path.join(__dirname, 'fixtures/chair'),\n        eggPath: '/path/to/eggPath',\n        cache: false,\n        coverage: false,\n      });\n      await app\n        .debug()\n        .expect('stdout', /\\/path\\/to\\/eggPath/)\n        .end();\n    });\n  });\n\n  describe('cluster with workers', () => {\n    let app;\n    after(() => app.close());\n\n    it('should get 2 workers', async () => {\n      app = mm.cluster({\n        baseDir: 'demo',\n        customEgg: path.join(__dirname, 'fixtures/chair'),\n        workers: 2,\n        cache: false,\n        coverage: false,\n      });\n      app.debug();\n      await app.expect('stdout', /app_worker#1:/)\n        .expect('stdout', /app_worker#2:/)\n        .end();\n    });\n  });\n\n  describe('cluster with opts.customEgg', () => {\n    let app;\n    after(() => app.close());\n\n    it('should pass execArgv', async () => {\n      app = mm.cluster({\n        baseDir: 'custom_egg',\n        customEgg: path.join(__dirname, 'fixtures/bar'),\n        workers: 1,\n        cache: false,\n        coverage: false,\n        opt: {\n          execArgv: [ '--inspect' ],\n        },\n      });\n      // app.debug();\n      await app.expect('stdout', /app_worker#1:/)\n        .expect('stderr', /Debugger listening/)\n        .end();\n    });\n  });\n\n  describe('cluster with egg.framework=yadan', () => {\n    let app;\n    after(() => app.close());\n\n    it('should pass execArgv', async () => {\n      app = mm.cluster({\n        baseDir: 'yadan_app',\n        workers: 1,\n        cache: false,\n        coverage: false,\n      });\n      await app.expect('stdout', /app_worker#1:/)\n        .end();\n    });\n  });\n\n  describe('prerequire', () => {\n    let app;\n    after(() => app.close());\n\n    it('should load files', async () => {\n      mm(process.env, 'EGG_BIN_PREREQUIRE', 'true');\n      mm(process.env, 'NODE_DEBUG', 'egg-mock:prerequire');\n      app = mm.cluster({\n        baseDir: 'yadan_app',\n        workers: 1,\n        cache: false,\n        coverage: false,\n      });\n      await app\n        .expect('stderr', /prerequire .+?\\/app\\/extend\\/application.js/)\n        .expect('code', 0)\n        .end();\n    });\n  });\n\n  describe('custom port', () => {\n    let app;\n    after(() => app.close());\n\n    it('should use it', async () => {\n      app = mm.cluster({\n        baseDir: path.join(fixtures, 'demo'),\n        cache: false,\n        coverage: false,\n        port: 5566,\n      });\n      // app.debug();\n      await app.ready();\n\n      app.expect('stdout', /egg started on http:\\/\\/127.0.0.1:5566/);\n    });\n  });\n});\n"
  },
  {
    "path": "test/ctx.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\n\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/ctx.test.js', () => {\n\n  afterEach(mm.restore);\n\n  let app;\n  before(done => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo'),\n    });\n    app.ready(done);\n  });\n  after(() => app.close());\n\n  it('should has logger, app, request', () => {\n    const ctx = app.mockContext();\n    assert(ctx.app instanceof Object);\n    assert(ctx.logger instanceof Object);\n    assert(ctx.coreLogger instanceof Object);\n    assert(ctx.request.url === '/');\n    assert(ctx.request.ip === '127.0.0.1');\n  });\n\n  it('should ctx.ip work', () => {\n    const ctx = app.mockContext();\n    ctx.request.headers['x-forwarded-for'] = '';\n    assert(ctx.request.ip === '127.0.0.1');\n  });\n\n  it('should has services', function* () {\n    const ctx = app.mockContext();\n    const data = yield ctx.service.foo.get('foo');\n    assert(data === 'bar');\n  });\n\n  it('should not override mockData', function* () {\n    const mockData = { user: 'popomore' };\n    app.mockContext(mockData);\n    app.mockContext(mockData);\n    assert(!mockData.headers);\n    assert(!mockData.method);\n  });\n\n  describe('mockContextScope', () => {\n    it('should not conflict with nest call', async () => {\n      await app.mockContextScope(async ctx => {\n        const currentStore = app.ctxStorage.getStore();\n        assert(ctx === currentStore);\n\n        await app.mockContextScope(async nestCtx => {\n          const currentStore = app.ctxStorage.getStore();\n          assert(nestCtx === currentStore);\n        });\n      });\n    });\n\n    it('should not conflict with concurrent call', async () => {\n      await Promise.all([\n        await app.mockContextScope(async ctx => {\n          const currentStore = app.ctxStorage.getStore();\n          assert(ctx === currentStore);\n        }),\n        await app.mockContextScope(async ctx => {\n          const currentStore = app.ctxStorage.getStore();\n          assert(ctx === currentStore);\n        }),\n      ]);\n\n    });\n  });\n\n\n});\n"
  },
  {
    "path": "test/fixtures/agent/agent.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst Client = require('./client');\n\nmodule.exports = agent => {\n  const done = agent.readyCallback('agent:agent');\n  const p = path.join(__dirname, 'run/test.txt');\n  fs.mkdirSync(path.join(__dirname, 'run'), { recursive: true });\n  fs.writeFile(p, '123', done);\n\n  agent.client = agent.cluster(Client).create();\n};\n"
  },
  {
    "path": "test/fixtures/agent/app.js",
    "content": "'use strict';\n\nconst fs = require('fs');\nconst path = require('path');\nconst Client = require('./client');\n\nmodule.exports = function(app) {\n  const done = app.readyCallback('agent:app');\n  const p = path.join(__dirname, 'run/test.txt');\n  setTimeout(() => {\n    fs.readFile(p, 'utf-8', done);\n  }, 1000);\n\n  app.client = app.cluster(Client).create();\n};\n"
  },
  {
    "path": "test/fixtures/agent/client.js",
    "content": "'use strict';\n\nconst Base = require('sdk-base');\n\nclass Client extends Base {\n  constructor() {\n    super();\n    this.ready(true);\n  }\n\n  subscribe(topic, listener) {\n    setTimeout(() => listener(topic), 10);\n  }\n}\n\nmodule.exports = Client;\n"
  },
  {
    "path": "test/fixtures/agent/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/agent/package.json",
    "content": "{\n  \"name\": \"demo\"\n}\n"
  },
  {
    "path": "test/fixtures/agent-boot-error/agent.js",
    "content": "'use strict';\n\nconst { FrameworkBaseError } = require('egg-errors');\nclass CustomError extends FrameworkBaseError {\n  get module() {\n    return 'customPlugin';\n  }\n}\n\nmodule.exports = class {\n  configWillLoad() {\n    throw new CustomError('mock error', 99);\n  }\n};\n"
  },
  {
    "path": "test/fixtures/agent-boot-error/package.json",
    "content": "{\n  \"name\": \"agent-boot-error\"\n}\n"
  },
  {
    "path": "test/fixtures/agent-boot-ready-error/agent.js",
    "content": "'use strict';\n\nconst { FrameworkBaseError } = require('egg-errors');\nclass CustomError extends FrameworkBaseError {\n  get module() {\n    return 'customPlugin';\n  }\n}\n\nmodule.exports = class {\n  async didLoad() {\n    throw new CustomError('mock error', 99);\n  }\n};\n"
  },
  {
    "path": "test/fixtures/agent-boot-ready-error/package.json",
    "content": "{\n  \"name\": \"agent-boot-ready-error\"\n}\n"
  },
  {
    "path": "test/fixtures/app/app/router.js",
    "content": "const { sleep } = require('../../../../lib/utils');\n\nmodule.exports = app => {\n  app.get('/', async ctx => {\n    ctx.body = 'foo';\n  });\n\n  app.get('/keepAliveTimeout', async ctx => {\n    ctx.body = {\n      keepAliveTimeout: ctx.app.serverKeepAliveTimeout,\n    };\n  });\n\n  app.get('/ua', async ctx => {\n    ctx.body = ctx.get('user-agent');\n  });\n\n  app.get('/logger', async ctx => {\n    ctx.logger.info('[app.expectLog() test] ok');\n    ctx.coreLogger.info('[app.expectLog(coreLogger) test] ok');\n    ctx.body = { ok: true };\n  });\n\n\n  let counter = 0;\n  app.get('/counter', async ctx => {\n    ctx.body = { counter };\n  });\n\n  app.get('/counter/plus', async ctx => {\n    ctx.runInBackground(async ctx => {\n      // mock io delay\n      await sleep(10);\n      if (ctx.superMan) {\n        counter += 10;\n        return;\n      }\n      counter++;\n    });\n    ctx.body = { counter };\n  });\n\n  app.get('/counter/minus', async ctx => {\n    ctx.runInBackground(async () => {\n      await sleep(10);\n      counter--;\n    });\n    ctx.body = { counter };\n  });\n\n  app.get('/counter/plusplus', async ctx => {\n    ctx.runInBackground(async ctx => {\n      // mock io delay\n      await sleep(10);\n      if (ctx.superMan) {\n        counter += 10;\n      } else {\n        counter++;\n      }\n      ctx.runInBackground(async ctx => {\n        // mock io delay\n        await sleep(10);\n        if (ctx.superMan) {\n          counter += 10;\n        } else {\n          counter++;\n        }\n      });\n    });\n    ctx.body = { counter };\n  });\n};\n"
  },
  {
    "path": "test/fixtures/app/app.js",
    "content": "'use strict';\n\nmodule.exports = app => {\n  app.on('server', server => {\n    app.serverKeepAliveTimeout = server.keepAliveTimeout || 5000;\n  });\n};\n"
  },
  {
    "path": "test/fixtures/app/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/app/package.json",
    "content": "{\n  \"name\": \"app\"\n}\n"
  },
  {
    "path": "test/fixtures/app-boot-error/app.js",
    "content": "'use strict';\n\nconst { FrameworkBaseError } = require('egg-errors');\nclass CustomError extends FrameworkBaseError {\n  get module() {\n    return 'customPlugin';\n  }\n}\n\nmodule.exports = class {\n  configWillLoad() {\n    throw new CustomError('mock error', 99);\n  }\n};\n"
  },
  {
    "path": "test/fixtures/app-boot-error/package.json",
    "content": "{\n  \"name\": \"app-boot-error\"\n}\n"
  },
  {
    "path": "test/fixtures/app-boot-ready-error/app.js",
    "content": "'use strict';\n\nconst { FrameworkBaseError } = require('egg-errors');\nclass CustomError extends FrameworkBaseError {\n  get module() {\n    return 'customPlugin';\n  }\n}\n\nmodule.exports = class {\n  async didLoad() {\n    throw new CustomError('mock error', 99);\n  }\n};\n"
  },
  {
    "path": "test/fixtures/app-boot-ready-error/package.json",
    "content": "{\n  \"name\": \"app-boot-ready-error\"\n}\n"
  },
  {
    "path": "test/fixtures/app-event/agent.js",
    "content": "'use strict';\n\nmodule.exports = app => {\n  app.ready(() => {\n    app.emit('agentInstantiated');\n  });\n};\n"
  },
  {
    "path": "test/fixtures/app-event/app/router.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  app.get('/event', function* () {\n    this.app.emit('eventByRequest');\n    this.body = 'done';\n  });\n};\n"
  },
  {
    "path": "test/fixtures/app-event/app.js",
    "content": "'use strict';\n\nconst { sleep } = require('../../../lib/utils');\n\nmodule.exports = app => {\n  app.ready(() => {\n    // after ready\n    app.emit('appReady');\n  });\n\n  process.nextTick(() => {\n    // before ready, after app instantiate\n    app.emit('appInstantiated');\n  });\n\n  app.beforeStart(function* () {\n    yield sleep(1000);\n  });\n};\n"
  },
  {
    "path": "test/fixtures/app-event/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/app-event/package.json",
    "content": "{\n  \"name\": \"app-event\"\n}\n"
  },
  {
    "path": "test/fixtures/app-fail/app/router.js",
    "content": "'use strict';\n\nthrow new Error('load error');\n"
  },
  {
    "path": "test/fixtures/app-fail/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/app-fail/package.json",
    "content": "{\n  \"name\": \"egg-mock\"\n}\n"
  },
  {
    "path": "test/fixtures/app-proxy/app/extend/application.js",
    "content": "'use strict';\n\nmodule.exports = {\n  get getter() {\n    return 'getter';\n  },\n  method() {\n    return 'method';\n  },\n  prop: 1,\n  shouldBeDelete: true,\n\n  get a() {\n    return 'a';\n  },\n  set a(x) {\n    this._a = x;\n  },\n};\n"
  },
  {
    "path": "test/fixtures/app-proxy/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/app-proxy/package.json",
    "content": "{\n  \"name\": \"app-proxy\"\n}\n"
  },
  {
    "path": "test/fixtures/app-proxy-ready/agent.js",
    "content": "'use strict';\n\nconst { sleep } = require('../../../lib/utils');\n\nmodule.exports = app => {\n  // set timeout let testcase ran before ready\n  app.beforeStart(function* () {\n    yield sleep(1000);\n  });\n};\n"
  },
  {
    "path": "test/fixtures/app-proxy-ready/app.js",
    "content": "'use strict';\n\nmodule.exports = app => {\n  app.emit('eventOnReady');\n  app.emit('eventOnReady');\n  app.emit('eventOnceReady');\n  app.emit('eventOnceReady');\n};\n"
  },
  {
    "path": "test/fixtures/app-proxy-ready/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/app-proxy-ready/package.json",
    "content": "{\n  \"name\": \"app-proxy-ready\"\n}\n"
  },
  {
    "path": "test/fixtures/app-ready-failed/app.js",
    "content": "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",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/app-ready-failed/package.json",
    "content": "{\n  \"name\": \"app\"\n}\n"
  },
  {
    "path": "test/fixtures/app-ready-failed/test/index.test.js",
    "content": "const assert = require('assert');\nconst { app } = require('../../../../bootstrap');\ndescribe('test for app ready failed', () => {\n  it('should not print', () => {\n    // ...\n    assert(app);\n  });\n});\n"
  },
  {
    "path": "test/fixtures/apps/app-not-clean/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/apps/app-not-clean/logs/keep",
    "content": ""
  },
  {
    "path": "test/fixtures/apps/app-not-clean/package.json",
    "content": "{\n  \"name\": \"app-not-clean\"\n}\n"
  },
  {
    "path": "test/fixtures/apps/app-throw/app/router.js",
    "content": "'use strict';\n\nmodule.exports = app => {\n  app.get('/throw', function* () {\n    this.body = 'foo';\n    setTimeout(() => {\n      /* eslint-disable-next-line */\n      a.b = c;\n    }, 1);\n  });\n\n  app.get('/throw-unhandledRejection', function* () {\n    this.body = 'foo';\n    new Promise((resolve, reject) => {\n      reject(new Error('foo reject error'));\n    });\n  });\n\n  app.get('/throw-unhandledRejection-string', function* () {\n    this.body = 'foo';\n    new Promise((resolve, reject) => {\n      reject(new Error('foo reject string error'));\n    });\n  });\n\n  app.get('/throw-unhandledRejection-obj', function* () {\n    this.body = 'foo';\n    new Promise((resolve, reject) => {\n      const err = {\n        name: 'TypeError',\n        message: 'foo reject obj error',\n        stack: new Error().stack,\n        toString() {\n          return this.name + ': ' + this.message;\n        },\n      };\n      reject(err);\n    });\n  });\n};\n"
  },
  {
    "path": "test/fixtures/apps/app-throw/config/config.default.js",
    "content": "'use strict';\n\nexports.keys = 'test key';\n"
  },
  {
    "path": "test/fixtures/apps/app-throw/config/config.unittest.js",
    "content": "'use strict';\n\nexports.logger = {\n  consoleLevel: 'NONE',\n};\n"
  },
  {
    "path": "test/fixtures/apps/app-throw/package.json",
    "content": "{\n  \"name\": \"app-throw\"\n}\n"
  },
  {
    "path": "test/fixtures/apps/barapp/app/controller/home.js",
    "content": "'use strict';\n\nmodule.exports = function* () {\n  this.body = {\n    foo: this.app.config.foo,\n    foobar: this.app.config.foobar,\n  };\n};\n"
  },
  {
    "path": "test/fixtures/apps/barapp/app/router.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  app.get('/', app.controller.home);\n};\n"
  },
  {
    "path": "test/fixtures/apps/barapp/config/config.default.js",
    "content": "'use strict';\n\nexports.foo = 'bar';\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/apps/barapp/package.json",
    "content": "{\n  \"name\": \"barapp\"\n}\n"
  },
  {
    "path": "test/fixtures/apps/env-app/config/config.default.js",
    "content": "'use strict';\n\nexports.fakeplugin = {\n  foo: 'bar-default',\n};\n\nexports.logger = {\n  consoleLevel: 'NONE',\n};\n\nexports.development = {\n  fastReady: false,\n};\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/apps/env-app/config/config.local.js",
    "content": "'use strict';\n\nexports.development = {\n  fastReady: false,\n};\n"
  },
  {
    "path": "test/fixtures/apps/env-app/config/config.prod.js",
    "content": "'use strict';\n\nexports.fakeplugin = {\n  foo: 'bar-prod',\n};\n"
  },
  {
    "path": "test/fixtures/apps/env-app/config/config.test.js",
    "content": "'use strict';\n\nexports.fakeplugin = {\n  foo: 'bar-test',\n};\n"
  },
  {
    "path": "test/fixtures/apps/env-app/config/config.unittest.js",
    "content": "'use strict';\n\nexports.fakeplugin = {\n  foo: 'bar-unittest',\n};\n"
  },
  {
    "path": "test/fixtures/apps/env-app/package.json",
    "content": "{\n  \"name\": \"env-app\"\n}\n"
  },
  {
    "path": "test/fixtures/apps/foo/app/router.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  app.get('/', function* () {\n    this.body = {\n      fooPlugin: app.fooPlugin,\n    };\n  });\n};\n"
  },
  {
    "path": "test/fixtures/apps/foo/config/config.default.js",
    "content": "'use strict';\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/apps/foo/package.json",
    "content": "{\n  \"name\": \"foo\"\n}\n"
  },
  {
    "path": "test/fixtures/apps/mock_cookies/app/router.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  app.get('/', function* () {\n    this.body = {\n      cookieValue: this.cookies.get('foo', { signed: false }) || undefined,\n      cookiesValue: this.cookies.get('foo', { signed: false }) || undefined,\n    };\n  });\n};\n"
  },
  {
    "path": "test/fixtures/apps/mock_cookies/config/config.default.js",
    "content": "'use strict';\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/apps/mock_cookies/package.json",
    "content": "{\n  \"name\": \"mockCookies\"\n}\n"
  },
  {
    "path": "test/fixtures/apps/mockhome/config/config.default.js",
    "content": "'use strict';\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/apps/mockhome/package.json",
    "content": "{\n  \"name\": \"mockhome\"\n}\n"
  },
  {
    "path": "test/fixtures/apps/no-framework/config/plugin.js",
    "content": "'use strict';\n\nconst path = require('path');\n\nmodule.exports = {\n  a: {\n    enable: true,\n    path: path.join(__dirname, '../plugin/a'),\n  },\n};\n"
  },
  {
    "path": "test/fixtures/apps/no-framework/package.json",
    "content": "{\n  \"name\": \"no-framework\"\n}\n"
  },
  {
    "path": "test/fixtures/apps/no-framework/plugin/a/app/extend/application.js",
    "content": "'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",
    "content": "{\n  \"eggPlugin\": {\n    \"name\": \"a\",\n    \"dependencies\": [\n      \"egg-mock\"\n    ]\n  }\n}\n"
  },
  {
    "path": "test/fixtures/apps/parallel-test/package.json",
    "content": "{\n  \"name\": \"foo\"\n}\n"
  },
  {
    "path": "test/fixtures/apps/parallel-test/test/a.test.js",
    "content": "const mm = require('../../../../../');\nconst assert = require('assert');\n\ndescribe('test/parallel_a.test.js', () => {\n  it('should work', () => {\n    mm(global, 'test', '233');\n    assert(global.test === '233');\n  });\n});\n"
  },
  {
    "path": "test/fixtures/apps/parallel-test/test/b.test.js",
    "content": "const mm = require('../../../../../');\nconst assert = require('assert');\n\ndescribe('test/parallel_b.test.js', () => {\n  it('should work', () => {\n    mm(global, 'test', '244');\n    assert(global.test === '244');\n  });\n});\n"
  },
  {
    "path": "test/fixtures/apps/parallel-test/test/c.test.js",
    "content": "const assert = require('assert');\n\ndescribe('test/parallel_a.test.js', () => {\n  it('should work', () => {\n    assert(!global.test);\n  });\n});\n"
  },
  {
    "path": "test/fixtures/bar/config/config.default.js",
    "content": "'use strict';\n\nexports.foobar = 'bar';\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/bar/index.js",
    "content": "'use strict';\n\nconst egg = require('egg');\nconst EGG_PATH = Symbol.for('egg#eggPath');\n\nclass BarApplication extends egg.Application {\n  get [EGG_PATH]() {\n    return __dirname;\n  }\n}\n\nObject.assign(exports, egg);\nexports.Application = BarApplication;\n"
  },
  {
    "path": "test/fixtures/bar/package.json",
    "content": "{\n  \"name\": \"bar\",\n  \"version\": \"1.0.0\"\n}\n"
  },
  {
    "path": "test/fixtures/cache/config.default.js",
    "content": "'use strict';\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/cache/package.json",
    "content": "{\n  \"name\": \"cache\"\n}\n"
  },
  {
    "path": "test/fixtures/chair/index.js",
    "content": "'use strict';\n\nconst egg = require('egg');\n\nfunction startCluster(options) {\n  // print for the testcase that will assert stdout\n  console.log(options.eggPath);\n  delete options.eggPath;\n  egg.startCluster(options);\n}\n\nObject.assign(exports, egg, { startCluster });\n"
  },
  {
    "path": "test/fixtures/chair/package.json",
    "content": "{\n  \"name\": \"chair\"\n}\n"
  },
  {
    "path": "test/fixtures/create-context-failed/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/create-context-failed/package.json",
    "content": "{\n  \"name\": \"app\"\n}\n"
  },
  {
    "path": "test/fixtures/create-context-failed/test/index.test.js",
    "content": "const { setGetAppCallback } = require('../../../..');\n\nsetGetAppCallback(() => {\n  return {\n    ready: async () => {\n      // ...\n    },\n    mockContextScope: async () => {\n      throw new Error('mock create context failed');\n    },\n    close: async () => {\n      // ...\n    },\n    backgroundTasksFinished: async () => {\n      // ...\n    },\n  };\n});\n\ndescribe('test case create context error', () => {\n  it('should not print', () => {\n  });\n});\n"
  },
  {
    "path": "test/fixtures/custom-loader/app/adapter/docker.js",
    "content": "'use strict';\n\nclass DockerAdapter {\n  constructor(app) {\n    this.app = app;\n  }\n\n  async inspectDocker() {\n    return 'docker';\n  }\n\n}\n\nmodule.exports = DockerAdapter;\n"
  },
  {
    "path": "test/fixtures/custom-loader/app/controller/user.js",
    "content": "'use strict';\n\nclass UserController {\n  constructor(ctx) {\n    this.ctx = ctx;\n    this.app = ctx.app;\n  }\n\n  async get() {\n    this.ctx.body = {\n      adapter: await this.app.adapter.docker.inspectDocker(),\n      repository: await this.ctx.repository.user.get(),\n    };\n  }\n}\n\nmodule.exports = UserController;\n"
  },
  {
    "path": "test/fixtures/custom-loader/app/repository/user.js",
    "content": "'use strict';\n\nclass UserRepository {\n  constructor(ctx) {\n    this.ctx = ctx;\n  }\n\n  async get() {\n    return this.ctx.params.name;\n  }\n\n}\n\nmodule.exports = UserRepository;\n"
  },
  {
    "path": "test/fixtures/custom-loader/app/router.js",
    "content": "'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",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n  customLoader: {\n    adapter: {\n      directory: 'app/adapter',\n      inject: 'app',\n    },\n    repository: {\n      directory: 'app/repository',\n      inject: 'ctx',\n    },\n    env: {\n      directory: 'app/env',\n      inject: 'ctx',\n    },\n  },\n};\n"
  },
  {
    "path": "test/fixtures/custom-loader/package.json",
    "content": "{\n  \"name\": \"custom-loader\"\n}\n"
  },
  {
    "path": "test/fixtures/custom_egg/package.json",
    "content": "{\n  \"name\": \"custom\"\n}\n"
  },
  {
    "path": "test/fixtures/demo/app/context.js",
    "content": "'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",
    "content": "const assert = require('assert');\n\nmodule.exports = app => {\n  return async function file(ctx) {\n    const ctxFromStorage = app.ctxStorage.getStore();\n    assert(ctxFromStorage !== ctx);\n    const stream = await ctx.getFileStream();\n    const fields = stream.fields;\n    ctx.body = {\n      fields,\n      filename: stream.filename,\n      user: ctx.user,\n      traceId: ctx.traceId,\n      ctxFromStorageUser: ctxFromStorage.user,\n      ctxFromStorageTraceId: ctxFromStorage.traceId,\n    };\n  };\n};\n"
  },
  {
    "path": "test/fixtures/demo/app/controller/home.js",
    "content": "'use strict';\n\nexports.get = function* () {\n  this.body = {\n    cookieValue: this.getCookie('foo') || undefined,\n    cookiesValue: this.cookies.get('foo') || undefined,\n    sessionValue: this.session.foo,\n  };\n};\n\nexports.post = function* () {\n  this.body = 'done';\n};\n\nexports.hello = function* () {\n  this.body = 'hi';\n};\n\nexports.service = function* () {\n  this.body = {\n    foo1: yield this.service.foo.get(),\n    foo2: yield this.service.bar.foo.get(),\n    foo3: this.service.foo.getSync(),\n    thirdService: yield this.service.third.bar.foo.get(),\n  };\n};\n\nexports.serviceOld = function* () {\n  this.body = yield this.service.old.test();\n};\n\nexports.header = function* () {\n  this.body = {\n    header: this.get('customheader'),\n  };\n};\n\nexports.urllib = function* () {\n  const url = 'http://' + this.host;\n  const method = this.query.method || 'request';\n  const data = this.query.data ? JSON.parse(this.query.data) : undefined;\n  const dataType = this.query.dataType;\n  let r = this.app.httpclient[method](url + '/mock_url', {\n    dataType,\n    data,\n  });\n  if (method === 'request') r = r.then(d => d);\n  const r1 = yield r;\n  const r2 = yield this.app.httpclient[method](url + '/mock_url', {\n    method: 'POST',\n    dataType,\n    data,\n    headers: {\n      'x-custom': 'custom',\n    },\n  });\n  this.body = {\n    get: Buffer.isBuffer(r1.data) ? r1.data.toString() : r1.data,\n    post: Buffer.isBuffer(r2.data) ? r2.data.toString() : r2.data,\n  };\n};\n\nexports.mockUrlGet = function* () {\n  this.body = 'url get';\n};\n\nexports.mockUrlPost = function* () {\n  this.body = 'url post';\n};\n\nexports.mockUrllibHeaders = function* () {\n  const url = 'http://' + this.host;\n  const method = this.query.method || 'request';\n  const res = yield this.app.httpclient[method](url + '/mock_url');\n  this.body = res.headers;\n};\n\nexports.dataType = function* () {\n  const url = 'http://' + this.host;\n  const res = yield this.app.httpclient.request(url + '/mock_url', {\n    dataType: 'json',\n  });\n  this.body = res.data;\n};\n"
  },
  {
    "path": "test/fixtures/demo/app/controller/session.js",
    "content": "'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",
    "content": "exports.get = function* () {\n  this.set('x-request-url', this.url);\n  this.body = this.user;\n};\n\nexports.post = function* () {\n  this.body = {\n    user: this.user,\n    params: this.request.body,\n  };\n};\n"
  },
  {
    "path": "test/fixtures/demo/app/extend/application.js",
    "content": "'use strict';\n\nmodule.exports = {\n  mockDevice(obj) {\n    obj.mock = true;\n    return obj;\n  },\n\n  * mockGenerator(obj) {\n    obj.mock = true;\n    return obj;\n  },\n\n  mockPromise(obj) {\n    obj.mock = true;\n    return Promise.resolve(obj);\n  },\n};\n"
  },
  {
    "path": "test/fixtures/demo/app/router.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  app.get('home', '/', app.controller.home.get);\n  app.get('/hello', app.controller.home.hello);\n  app.get('/service', app.controller.home.service);\n  app.get('/service/old', app.controller.home.serviceOld);\n  app.get('/header', app.controller.home.header);\n  app.get('/urllib', app.controller.home.urllib);\n  app.get('/mock_url', app.controller.home.mockUrlGet);\n  app.post('/mock_url', app.controller.home.mockUrlPost);\n  app.get('/mock_urllib', app.controller.home.mockUrllibHeaders);\n  app.get('/data_type', app.controller.home.dataType);\n  app.get('session', '/session', app.controller.session);\n\n  app.post('/', app.controller.home.post);\n\n  app.get('/user', app.controller.user.get);\n  app.post('/user', app.controller.user.post);\n  app.post('/file', app.controller.file);\n};\n"
  },
  {
    "path": "test/fixtures/demo/app/service/bar/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    * get() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/demo/app/service/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    * get() {\n      return 'bar';\n    }\n\n    getSync() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/demo/app/service/old.js",
    "content": "'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",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Main extends app.Service {\n    * get() {\n      return 'third';\n    }\n  }\n\n  return Main;\n};\n"
  },
  {
    "path": "test/fixtures/demo/app.js",
    "content": "'use strict';\n\nmodule.exports = function() {\n\n};\n"
  },
  {
    "path": "test/fixtures/demo/config/config.js",
    "content": "'use strict';\n\nmodule.exports = {\n  urllib: {\n    keepAlive: false,\n  },\n  logger: {\n    consoleLevel: 'NONE',\n  },\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/demo/mocks_data/service/bar/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/demo/mocks_data/service/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/demo/package.json",
    "content": "{\n  \"name\": \"demo\"\n}\n"
  },
  {
    "path": "test/fixtures/demo-async/app/controller/home.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Home extends app.Controller {\n    async testService() {\n      this.ctx.body = {\n        foo1: await this.service.foo.get(),\n        foo2: await this.service.bar.foo.get(),\n        foo3: this.service.foo.getSync(),\n        thirdService: await this.service.third.bar.foo.get(),\n      };\n    }\n  }\n\n  return Home;\n};\n"
  },
  {
    "path": "test/fixtures/demo-async/app/router.js",
    "content": "'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",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    async get() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/demo-async/app/service/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    async get() {\n      return 'bar';\n    }\n\n    getSync() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/demo-async/app/service/third/bar/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Main extends app.Service {\n    async get() {\n      return 'third';\n    }\n  }\n\n  return Main;\n};\n"
  },
  {
    "path": "test/fixtures/demo-async/app.js",
    "content": "'use strict';\n\nmodule.exports = function() {\n\n};\n"
  },
  {
    "path": "test/fixtures/demo-async/config/config.js",
    "content": "'use strict';\n\nmodule.exports = {\n  urllib: {\n    keepAlive: false,\n  },\n  logger: {\n    consoleLevel: 'NONE',\n  },\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/demo-async/mocks_data/service/bar/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/demo-async/mocks_data/service/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/demo-async/package.json",
    "content": "{\n  \"name\": \"demo-async\"\n}\n"
  },
  {
    "path": "test/fixtures/demo_next/app/context.js",
    "content": "'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",
    "content": "'use strict';\n\nmodule.exports = function* () {\n  const stream = yield this.getFileStream();\n  const fields = stream.fields;\n  this.body = {\n    fields,\n    filename: stream.filename,\n    user: this.user,\n  };\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/app/controller/home.js",
    "content": "'use strict';\n\nexports.get = function* () {\n  this.body = {\n    cookieValue: this.getCookie('foo') || undefined,\n    cookiesValue: this.cookies.get('foo') || undefined,\n    sessionValue: this.session.foo,\n  };\n};\n\nexports.post = function* () {\n  this.body = 'done';\n};\n\nexports.hello = function* () {\n  this.body = 'hi';\n};\n\nexports.service = function* () {\n  this.body = {\n    foo1: yield this.service.foo.get(),\n    foo2: yield this.service.bar.foo.get(),\n    foo3: this.service.foo.getSync(),\n    thirdService: yield this.service.third.bar.foo.get(),\n  };\n};\n\nexports.serviceOld = function* () {\n  this.body = yield this.service.old.test();\n};\n\nexports.header = function* () {\n  this.body = {\n    header: this.get('customheader'),\n  };\n};\n\nexports.urllib = function* () {\n  const url = 'http://' + this.host;\n  const method = this.query.method || 'request';\n  const data = this.query.data ? JSON.parse(this.query.data) : undefined;\n  const dataType = this.query.dataType;\n  const foo = this.query.foo;\n  let requestUrl = url + (this.query.mock_url || '/mock_url');\n  if (foo) {\n    requestUrl = `${requestUrl}?foo=${foo}`;\n  }\n  let r = this.app.httpclient[method](requestUrl, {\n    dataType,\n    data,\n  });\n  if (method === 'request') r = r.then(d => d);\n  const r1 = yield r;\n  const r2 = yield this.app.httpclient[method](requestUrl, {\n    method: 'POST',\n    dataType,\n    data,\n    headers: {\n      'x-custom': 'custom',\n    },\n  });\n  this.body = {\n    get: Buffer.isBuffer(r1.data) ? r1.data.toString() : r1.data,\n    post: Buffer.isBuffer(r2.data) ? r2.data.toString() : r2.data,\n  };\n};\n\nexports.streaming = async ctx => {\n  const url = 'http://' + ctx.host;\n  const response = await ctx.httpclient.request(url + '/mock_url', {\n    method: 'GET',\n    streaming: true,\n  });\n  ctx.status = response.status;\n  ctx.body = response.res;\n};\n\nexports.mockUrlGet = function* () {\n  const foo = this.query.foo;\n  if (foo) {\n    this.body = `url get with foo: ${foo}`;\n    return;\n  }\n  this.body = 'url get';\n};\n\nexports.mockUrlPost = function* () {\n  this.body = 'url post';\n};\n\nexports.mockUrllibHeaders = function* () {\n  const url = 'http://' + this.host;\n  const method = this.query.method || 'request';\n  const res = yield this.app.httpclient[method](url + '/mock_url');\n  this.body = res.headers;\n};\n\nexports.dataType = function* () {\n  const url = 'http://' + this.host;\n  const res = yield this.app.httpclient.request(url + '/mock_url', {\n    dataType: 'json',\n  });\n  this.body = res.data;\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/app/controller/session.js",
    "content": "'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",
    "content": "'use strict';\n\nexports.get = function* () {\n  this.body = this.user;\n};\n\nexports.post = function* () {\n  this.body = {\n    user: this.user,\n    params: this.request.body,\n  };\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/app/extend/application.js",
    "content": "'use strict';\n\nmodule.exports = {\n  mockDevice(obj) {\n    obj.mock = true;\n    return obj;\n  },\n\n  * mockGenerator(obj) {\n    obj.mock = true;\n    return obj;\n  },\n\n  mockPromise(obj) {\n    obj.mock = true;\n    return Promise.resolve(obj);\n  },\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/app/router.js",
    "content": "module.exports = app => {\n  app.get('home', '/', app.controller.home.get);\n  app.get('/hello', app.controller.home.hello);\n  app.get('/service', app.controller.home.service);\n  app.get('/service/old', app.controller.home.serviceOld);\n  app.get('/header', app.controller.home.header);\n  app.get('/urllib', app.controller.home.urllib);\n  app.get('/mock_url', app.controller.home.mockUrlGet);\n  app.get('/mock_url2', app.controller.home.mockUrlGet);\n  app.post('/mock_url', app.controller.home.mockUrlPost);\n  app.post('/mock_url2', app.controller.home.mockUrlPost);\n  app.get('/mock_urllib', app.controller.home.mockUrllibHeaders);\n  app.get('/data_type', app.controller.home.dataType);\n  app.get('session', '/session', app.controller.session);\n\n  app.post('/', app.controller.home.post);\n\n  app.get('/user', app.controller.user.get);\n  app.post('/user', app.controller.user.post);\n  app.post('/file', app.controller.file);\n\n  app.get('/streaming', 'home.streaming');\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/app/service/bar/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    * get() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/app/service/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    * get() {\n      return 'bar';\n    }\n\n    getSync() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/app/service/old.js",
    "content": "'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",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Main extends app.Service {\n    * get() {\n      return 'third';\n    }\n  }\n\n  return Main;\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/app.js",
    "content": "'use strict';\n\nmodule.exports = function() {\n\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/config/config.js",
    "content": "module.exports = {\n  httpclient: {\n    useHttpClientNext: true,\n    request: {\n      timing: true,\n    },\n  },\n  logger: {\n    consoleLevel: 'NONE',\n  },\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/demo_next/mocks_data/service/bar/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/demo_next/mocks_data/service/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/demo_next/package.json",
    "content": "{\n  \"name\": \"demo\"\n}\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/app/context.js",
    "content": "'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",
    "content": "'use strict';\n\nmodule.exports = function* () {\n  const stream = yield this.getFileStream();\n  const fields = stream.fields;\n  this.body = {\n    fields,\n    filename: stream.filename,\n    user: this.user,\n  };\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/app/controller/home.js",
    "content": "'use strict';\n\nexports.get = function* () {\n  this.body = {\n    cookieValue: this.getCookie('foo') || undefined,\n    cookiesValue: this.cookies.get('foo') || undefined,\n    sessionValue: this.session.foo,\n  };\n};\n\nexports.post = function* () {\n  this.body = 'done';\n};\n\nexports.hello = function* () {\n  this.body = 'hi';\n};\n\nexports.service = function* () {\n  this.body = {\n    foo1: yield this.service.foo.get(),\n    foo2: yield this.service.bar.foo.get(),\n    foo3: this.service.foo.getSync(),\n    thirdService: yield this.service.third.bar.foo.get(),\n  };\n};\n\nexports.serviceOld = function* () {\n  this.body = yield this.service.old.test();\n};\n\nexports.header = function* () {\n  this.body = {\n    header: this.get('customheader'),\n  };\n};\n\nexports.urllib = function* () {\n  const url = 'http://' + this.host;\n  const method = this.query.method || 'request';\n  const data = this.query.data ? JSON.parse(this.query.data) : undefined;\n  const dataType = this.query.dataType;\n  const foo = this.query.foo;\n  let requestUrl = url + (this.query.mock_url || '/mock_url');\n  if (foo) {\n    requestUrl = `${requestUrl}?foo=${foo}`;\n  }\n  let r = this.app.httpclient[method](requestUrl, {\n    dataType,\n    data,\n  });\n  if (method === 'request') r = r.then(d => d);\n  const r1 = yield r;\n  const r2 = yield this.app.httpclient[method](requestUrl, {\n    method: 'POST',\n    dataType,\n    data,\n    headers: {\n      'x-custom': 'custom',\n    },\n  });\n  this.body = {\n    get: Buffer.isBuffer(r1.data) ? r1.data.toString() : r1.data,\n    post: Buffer.isBuffer(r2.data) ? r2.data.toString() : r2.data,\n  };\n};\n\nexports.streaming = async ctx => {\n  const url = 'http://' + ctx.host;\n  const response = await ctx.httpclient.request(url + '/mock_url', {\n    method: 'GET',\n    streaming: true,\n  });\n  ctx.status = response.status;\n  ctx.body = response.res;\n};\n\nexports.mockUrlGet = function* () {\n  const foo = this.query.foo;\n  if (foo) {\n    this.body = `url get with foo: ${foo}`;\n    return;\n  }\n  this.body = 'url get';\n};\n\nexports.mockUrlPost = function* () {\n  this.body = 'url post';\n};\n\nexports.mockUrllibHeaders = function* () {\n  const url = 'http://' + this.host;\n  const method = this.query.method || 'request';\n  const res = yield this.app.httpclient[method](url + '/mock_url');\n  this.body = res.headers;\n};\n\nexports.dataType = function* () {\n  const url = 'http://' + this.host;\n  const res = yield this.app.httpclient.request(url + '/mock_url', {\n    dataType: 'json',\n  });\n  this.body = res.data;\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/app/controller/session.js",
    "content": "'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",
    "content": "'use strict';\n\nexports.get = function* () {\n  this.body = this.user;\n};\n\nexports.post = function* () {\n  this.body = {\n    user: this.user,\n    params: this.request.body,\n  };\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/app/extend/application.js",
    "content": "'use strict';\n\nmodule.exports = {\n  mockDevice(obj) {\n    obj.mock = true;\n    return obj;\n  },\n\n  * mockGenerator(obj) {\n    obj.mock = true;\n    return obj;\n  },\n\n  mockPromise(obj) {\n    obj.mock = true;\n    return Promise.resolve(obj);\n  },\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/app/router.js",
    "content": "module.exports = app => {\n  app.get('home', '/', app.controller.home.get);\n  app.get('/hello', app.controller.home.hello);\n  app.get('/service', app.controller.home.service);\n  app.get('/service/old', app.controller.home.serviceOld);\n  app.get('/header', app.controller.home.header);\n  app.get('/urllib', app.controller.home.urllib);\n  app.get('/mock_url', app.controller.home.mockUrlGet);\n  app.get('/mock_url2', app.controller.home.mockUrlGet);\n  app.post('/mock_url', app.controller.home.mockUrlPost);\n  app.post('/mock_url2', app.controller.home.mockUrlPost);\n  app.get('/mock_urllib', app.controller.home.mockUrllibHeaders);\n  app.get('/data_type', app.controller.home.dataType);\n  app.get('session', '/session', app.controller.session);\n\n  app.post('/', app.controller.home.post);\n\n  app.get('/user', app.controller.user.get);\n  app.post('/user', app.controller.user.post);\n  app.post('/file', app.controller.file);\n\n  app.get('/streaming', 'home.streaming');\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/app/service/bar/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    * get() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/app/service/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    * get() {\n      return 'bar';\n    }\n\n    getSync() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/app/service/old.js",
    "content": "'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",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Main extends app.Service {\n    * get() {\n      return 'third';\n    }\n  }\n\n  return Main;\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/app.js",
    "content": "'use strict';\n\nmodule.exports = function() {\n\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/config/config.js",
    "content": "module.exports = {\n  httpclient: {\n    useHttpClientNext: true,\n    allowH2: true,\n    request: {\n      timing: true,\n    },\n  },\n  logger: {\n    consoleLevel: 'NONE',\n  },\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/mocks_data/service/bar/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/mocks_data/service/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/demo_next_h2/package.json",
    "content": "{\n  \"name\": \"demo\"\n}\n"
  },
  {
    "path": "test/fixtures/disable-security/app/context.js",
    "content": "'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",
    "content": "'use strict';\n\nexports.get = function* () {\n  this.body = {\n    cookieValue: this.getCookie('foo') || undefined,\n    cookiesValue: this.cookies.get('foo') || undefined,\n    sessionValue: this.session.foo,\n  };\n};\n\nexports.post = function* () {\n  this.body = 'done';\n};\n\nexports.hello = function* () {\n  this.body = 'hi';\n};\n\nexports.service = function* () {\n  this.body = {\n    foo1: yield this.service.foo.get(),\n    foo2: yield this.service.bar.foo.get(),\n    foo3: this.service.foo.getSync(),\n    thirdService: yield this.service.third.bar.foo.get(),\n  };\n};\n\nexports.serviceOld = function* () {\n  this.body = yield this.service.old.test();\n};\n\nexports.header = function* () {\n  this.body = {\n    header: this.get('customheader'),\n  };\n};\n\nexports.urllib = function* () {\n  const url = 'http://' + this.host;\n  const method = this.query.method || 'request';\n  const dataType = this.query.dataType;\n  let r = this.app.httpclient[method](url + '/mock_url', {\n    dataType,\n  });\n  if (method === 'request') r = r.then(d => d);\n  const r1 = yield r;\n  const r2 = yield this.app.httpclient[method](url + '/mock_url', {\n    method: 'POST',\n    dataType,\n  });\n  this.body = {\n    get: Buffer.isBuffer(r1.data) ? r1.data.toString() : r1.data,\n    post: Buffer.isBuffer(r2.data) ? r2.data.toString() : r2.data,\n  };\n};\n\nexports.mockUrlGet = function* () {\n  this.body = 'url get';\n};\n\nexports.mockUrlPost = function* () {\n  this.body = 'url post';\n};\n\nexports.mockUrllibHeaders = function* () {\n  const url = 'http://' + this.host;\n  const method = this.query.method || 'request';\n  const res = yield this.app.httpclient[method](url + '/mock_url');\n  this.body = res.headers;\n};\n"
  },
  {
    "path": "test/fixtures/disable-security/app/controller/session.js",
    "content": "'use strict';\n\nmodule.exports = function* () {\n  this.body = this.session;\n};\n"
  },
  {
    "path": "test/fixtures/disable-security/app/router.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  app.get('/', app.controller.home.get);\n  app.get('/hello', app.controller.home.hello);\n  app.get('/service', app.controller.home.service);\n  app.get('/service/old', app.controller.home.serviceOld);\n  app.get('/header', app.controller.home.header);\n  app.get('/urllib', app.controller.home.urllib);\n  app.get('/mock_url', app.controller.home.mockUrlGet);\n  app.post('/mock_url', app.controller.home.mockUrlPost);\n  app.get('/mock_urllib', app.controller.home.mockUrllibHeaders);\n  app.get('/session', app.controller.session);\n\n  app.post('/', app.controller.home.post);\n};\n"
  },
  {
    "path": "test/fixtures/disable-security/app/service/bar/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    * get() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/disable-security/app/service/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Foo extends app.Service {\n    * get() {\n      return 'bar';\n    }\n\n    getSync() {\n      return 'bar';\n    }\n  }\n\n  return Foo;\n};\n"
  },
  {
    "path": "test/fixtures/disable-security/app/service/old.js",
    "content": "'use strict';\n\nmodule.exports = () => {\n  exports.test = function* () {\n    return 'hello';\n  };\n\n  return exports;\n};\n"
  },
  {
    "path": "test/fixtures/disable-security/app/service/third/bar/foo.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  class Main extends app.Service {\n    * get() {\n      return 'third';\n    }\n  }\n\n  return Main;\n};\n"
  },
  {
    "path": "test/fixtures/disable-security/app.js",
    "content": "'use strict';\n\nmodule.exports = function() {\n\n};\n"
  },
  {
    "path": "test/fixtures/disable-security/config/config.js",
    "content": "'use strict';\n\nmodule.exports = {\n  urllib: {\n    keepAlive: false,\n  },\n  logger: {\n    consoleLevel: 'NONE',\n  },\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/disable-security/config/plugin.js",
    "content": "'use strict';\n\nexports.security = false;\n"
  },
  {
    "path": "test/fixtures/disable-security/mocks_data/service/bar/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/disable-security/mocks_data/service/foo/get/foobar.js",
    "content": "'use strict';\n\nmodule.exports = 'foobar';\n"
  },
  {
    "path": "test/fixtures/disable-security/package.json",
    "content": "{\n  \"name\": \"demo\"\n}\n"
  },
  {
    "path": "test/fixtures/error-framework/index.js",
    "content": "'use strict';\n\nconst egg = require('egg');\n\nclass Application extends egg.Application {\n  constructor() {\n    throw new Error('start error');\n  }\n}\n\nObject.assign(exports, egg, { Application });\n"
  },
  {
    "path": "test/fixtures/error-framework/package.json",
    "content": "{\n  \"name\": \"error-framework\"\n}\n"
  },
  {
    "path": "test/fixtures/failed-app/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/failed-app/package.json",
    "content": "{\n  \"name\": \"app\"\n}\n"
  },
  {
    "path": "test/fixtures/failed-app/test/index.test.js",
    "content": "const assert = require('assert');\n\ndescribe('test/index.test.ts', () => {\n  describe('before error', () => {\n    before(() => {\n      throw new Error('before error');\n    });\n\n    it('should not print', () => {\n      assert.fail('never arrive');\n    });\n  });\n\n  describe('after error', () => {\n    after(() => {\n      throw new Error('after error');\n    });\n\n    it('should print', () => {\n      console.log('after error test case should print');\n    });\n  });\n\n  describe('beforeEach error', () => {\n    beforeEach(() => {\n      throw new Error('beforeEach error');\n    });\n\n    it('should not print', () => {\n      assert.fail('never arrive');\n    });\n  });\n\n  describe('afterEach error', () => {\n    afterEach(() => {\n      throw new Error('afterEach error');\n    });\n\n    it('should print', () => {\n      console.log('afterEach error test case should print');\n    });\n  });\n\n  describe('case error', () => {\n    it('should failed', () => {\n      assert.fail('should fail');\n    });\n\n    it('should work', () => {\n      // ...\n    });\n  });\n});\n"
  },
  {
    "path": "test/fixtures/fooPlugin/app.js",
    "content": "'use strict';\n\nmodule.exports = function(app) {\n  app.fooPlugin = true;\n};\n"
  },
  {
    "path": "test/fixtures/fooPlugin/config/config.default.js",
    "content": "'use strict';\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/fooPlugin/config/plugin.js",
    "content": "'use strict';\n\nexports.fooPlugin = {\n\n};\n"
  },
  {
    "path": "test/fixtures/fooPlugin/package.json",
    "content": "{\n  \"name\": \"fooPlugin\",\n  \"eggPlugin\": {\n    \"name\": \"fooPlugin\"\n  }\n}\n"
  },
  {
    "path": "test/fixtures/get-app-failed/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/get-app-failed/package.json",
    "content": "{\n  \"name\": \"app\"\n}\n"
  },
  {
    "path": "test/fixtures/get-app-failed/test/index.test.js",
    "content": "const { setGetAppCallback } = require('../../../..');\n\nsetGetAppCallback(() => {\n  throw new Error('mock get app failed');\n});\n\ndescribe('test case create context error', () => {\n  it('should not print', () => {\n  });\n});\n"
  },
  {
    "path": "test/fixtures/messenger-binding/agent.js",
    "content": "'use strict';\n\nmodule.exports = agent => {\n  agent.received = [];\n  agent.messenger.on('action', data => agent.received.push(data));\n\n  agent.messenger.on('broadcast-action', () => {\n    agent.recievedBroadcastAction = true;\n    agent.messenger.sendToApp('agent-recieved-broadcast-action');\n  });\n\n  agent.messenger.sendToApp('action', 'send data when agent starting');\n  agent.ready(() => {\n    agent.messenger.sendToApp('action', 'send data when agent started');\n  });\n  agent.messenger.on('egg-ready', () => {\n    agent.messenger.sendToApp('action', 'send data when server started');\n    process.nextTick(() => agent.messenger.sendRandom('action', 'send data to a random app'));\n  });\n  agent.messenger.on('egg-ready', data => {\n    agent.eggReady = true;\n    agent.eggReadyData = data;\n  });\n};\n"
  },
  {
    "path": "test/fixtures/messenger-binding/app.js",
    "content": "'use strict';\n\nmodule.exports = app => {\n  app.received = [];\n  app.messenger.on('action', data => app.received.push(data));\n\n  app.messenger.on('app-action', () => {\n    app.recievedAppAction = true;\n  });\n\n  app.messenger.on('broadcast-action', () => {\n    app.recievedBroadcastAction = true;\n  });\n\n  app.messenger.on('agent-recieved-broadcast-action', () => {\n    app.recievedAgentRecievedAction = true;\n  });\n\n  app.messenger.sendToAgent('action', 'send data when app starting');\n\n  app.ready(() => {\n    app.messenger.sendToAgent('action', 'send data when app started');\n    app.messenger.sendRandom('action', 'send data to a random agent')\n    app.messenger.broadcast('broadcast-action', 'broadcast action');\n    app.messenger.sendToApp('app-action', 'send action to app');\n  });\n  app.messenger.on('egg-ready', data => {\n    app.eggReady = true;\n    app.eggReadyData = data;\n  });\n};\n"
  },
  {
    "path": "test/fixtures/messenger-binding/config/config.default.js",
    "content": "'use strict';\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/messenger-binding/package.json",
    "content": "{\n  \"name\": \"messenger-binding\"\n}\n"
  },
  {
    "path": "test/fixtures/plugin/package.json",
    "content": "{\n  \"eggPlugin\": {\n    \"name\": \"plugin1\"\n  }\n}\n"
  },
  {
    "path": "test/fixtures/plugin-bootstrap/package.json",
    "content": "{\n  \"eggPlugin\": {\n    \"name\": \"plugin1\"\n  }\n}\n"
  },
  {
    "path": "test/fixtures/plugin-bootstrap/test.js",
    "content": "'use strict';\n\nrequire('../../../bootstrap');\n"
  },
  {
    "path": "test/fixtures/plugin_throw/package.json",
    "content": "{}\n"
  },
  {
    "path": "test/fixtures/request/app/router.js",
    "content": "'use strict';\n\nmodule.exports = app => {\n  app.get('home', '/', function* () {\n    this.body = 'hello world';\n  });\n\n  app.get('session', '/session', function* () {\n    this.body = 'hello session';\n  });\n};\n"
  },
  {
    "path": "test/fixtures/request/config/config.default.js",
    "content": "'use strict';\n\nexports.keys = 'foo';\n"
  },
  {
    "path": "test/fixtures/request/package.json",
    "content": "{\n  \"name\": \"request-demo\"\n}\n"
  },
  {
    "path": "test/fixtures/server/app.js",
    "content": "'use strict';\n\nmodule.exports = app => {\n  app.messenger.on('egg-ready', server => {\n    app.emitServer = !!server;\n  });\n};\n"
  },
  {
    "path": "test/fixtures/server/package.json",
    "content": "{\n  \"name\": \"server\",\n  \"version\": \"1.0.0\"\n}\n"
  },
  {
    "path": "test/fixtures/setup-app/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/setup-app/package.json",
    "content": "{\n  \"name\": \"app\"\n}\n"
  },
  {
    "path": "test/fixtures/setup-app/test/.setup.js",
    "content": "const mm = require('../../../../index');\nconst path = require('path');\nbefore(async () => {\n  global.app = mm.app({\n    baseDir: path.join(__dirname, '../'),\n    framework: require.resolve('egg'),\n  });\n  mm.setGetAppCallback(() => {\n    return global.app;\n  });\n  await global.app.ready();\n});\n"
  },
  {
    "path": "test/fixtures/setup-app/test/index.test.js",
    "content": "const assert = require('assert');\n\ndescribe('test/index.test.ts', () => {\n  it('should work', () => {\n    // eslint-disable-next-line no-undef\n    assert(app.currentContext);\n  });\n});\n"
  },
  {
    "path": "test/fixtures/tegg-app/app/modules/foo/LogService.ts",
    "content": "import { AccessLevel, Inject, SingletonProto } from '@eggjs/tegg';\n\ninterface Tracer {\n  traceId: string;\n}\n\n@SingletonProto({\n  accessLevel: AccessLevel.PUBLIC,\n})\nexport class LogService {\n  @Inject()\n  private readonly tracer: Tracer;\n\n  getTracerId() {\n    return this.tracer.traceId;\n  }\n}\n"
  },
  {
    "path": "test/fixtures/tegg-app/app/modules/foo/package.json",
    "content": "{\n  \"name\": \"foo\",\n  \"eggModule\": {\n    \"name\": \"foo\"\n  }\n}\n"
  },
  {
    "path": "test/fixtures/tegg-app/app.js",
    "content": "module.exports = app => {\n  app.on('server', server => {\n    app.serverKeepAliveTimeout = server.keepAliveTimeout || 5000;\n  });\n};\n"
  },
  {
    "path": "test/fixtures/tegg-app/config/config.default.js",
    "content": "module.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/tegg-app/config/plugin.js",
    "content": "module.exports = {\n  teggConfig: {\n    package: '@eggjs/tegg-config',\n    enable: true,\n  },\n  tegg: {\n    package: '@eggjs/tegg-plugin',\n    enable: true,\n  },\n  teggController: {\n    package: '@eggjs/tegg-controller-plugin',\n    enable: true,\n  },\n  tracer: {\n    package: 'egg-tracer',\n    enable: true,\n  },\n};\n"
  },
  {
    "path": "test/fixtures/tegg-app/package.json",
    "content": "{\n  \"name\": \"app\",\n  \"egg\": {\n    \"typescript\": true\n  }\n}\n"
  },
  {
    "path": "test/fixtures/tegg-app/test/hooks.test.ts",
    "content": "import assert from 'assert';\nimport { Context } from 'egg';\nimport { app } from '../../../../bootstrap';\n\ndescribe('test/hooks.test.ts', () => {\n  let beforeCtx;\n  let afterCtx;\n  let beforeEachCtxList: Record<string, Context> = {};\n  let afterEachCtxList: Record<string, Context> = {};\n  let itCtxList: Record<string, Context> = {};\n\n  before(async () => {\n    beforeCtx = app.currentContext;\n  });\n\n  after(() => {\n    afterCtx = app.currentContext;\n    assert(beforeCtx);\n    assert(beforeCtx !== itCtxList['foo']);\n    assert(itCtxList['foo'] !== itCtxList['bar']);\n    assert(afterCtx === beforeCtx);\n    assert(beforeEachCtxList['foo'] === afterEachCtxList['foo']);\n    assert(beforeEachCtxList['foo'] === itCtxList['foo']);\n  });\n\n  describe('foo', () => {\n    beforeEach(() => {\n      beforeEachCtxList['foo'] = app.currentContext;\n    });\n\n    it('should work', () => {\n      itCtxList['foo'] = app.currentContext;\n    });\n\n    afterEach(() => {\n      afterEachCtxList['foo'] = app.currentContext;\n    });\n  });\n\n  describe('bar', () => {\n    beforeEach(() => {\n      beforeEachCtxList['bar'] = app.currentContext;\n    });\n\n    it('should work', () => {\n      itCtxList['bar'] = app.currentContext;\n    });\n\n    afterEach(() => {\n      afterEachCtxList['bar'] = app.currentContext;\n    });\n  });\n\n  describe('multi it', () => {\n    const itCtxList: Array<Context> = [];\n\n    it('should work 1', () => {\n      itCtxList.push(app.currentContext);\n    });\n\n    it('should work 2', () => {\n      itCtxList.push(app.currentContext);\n    });\n\n    after(() => {\n      assert(itCtxList[0] !== itCtxList[1]);\n    })\n  });\n});\n"
  },
  {
    "path": "test/fixtures/tegg-app/test/multi_mock_context.test.ts",
    "content": "import assert from 'assert';\nimport { app } from '../../../../bootstrap';\n\ndescribe('test/multi_mock_context.test.ts', () => {\n  describe('mockContext', () => {\n    it('should only reused once', async () => {\n      const currentContext = app.currentContext;\n      const ctx1 = app.mockContext();\n      const ctx2 = app.mockContext();\n      assert.strictEqual(currentContext, ctx1);\n      assert.notStrictEqual(ctx2, ctx1);\n    });\n  });\n});\n"
  },
  {
    "path": "test/fixtures/tegg-app/test/tegg.test.ts",
    "content": "import assert from 'assert';\nimport { app } from '../../../../bootstrap';\nimport { LogService } from '../app/modules/foo/LogService';\n\ndescribe('test/tegg.test.ts', () => {\n  describe('async function', () => {\n    it('should work', async () => {\n      const logService = await app.getEggObject(LogService);\n      assert(logService.getTracerId());\n    });\n  });\n\n  describe('callback function', () => {\n    it('should work', (done) => {\n      app.mockModuleContextScope(async () => {\n        const logService = await app.getEggObject(LogService);\n        assert(logService.getTracerId());\n        done();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/fixtures/tegg-app/test/tegg_context.test.ts",
    "content": "import assert from 'assert';\nimport { Context } from 'egg';\nimport { app, mm } from '../../../../bootstrap';\nimport { LogService } from '../app/modules/foo/LogService';\n\ndescribe('test/tegg_context.test.ts', () => {\n  let ctx: Context;\n  let logService: LogService;\n  before(async () => {\n    logService = await app.getEggObject(LogService);\n  });\n\n  describe('mock ctx property', () => {\n    it('should mock ctx work', async () => {\n      ctx = await app.mockModuleContext();\n      mm(ctx.tracer, 'traceId', 'mockTraceId');\n      const traceId = logService.getTracerId();\n      assert.strictEqual(traceId, 'mockTraceId');\n    });\n  });\n\n  describe.skip('mockModuleContextWithData', () => {\n    let ctx: Context;\n\n    beforeEach(async () => {\n      ctx = await app.mockModuleContext({\n        tracer: {\n          traceId: 'mock_with_data',\n        },\n        headers: {\n          'user-agent': 'mock_agent',\n        },\n      });\n      assert.strictEqual(ctx.tracer.traceId, 'mock_with_data');\n      assert.strictEqual(ctx.get('user-agent'), 'mock_agent');\n    });\n\n    it('should mock ctx work', () => {\n      const traceId = logService.getTracerId();\n      assert.strictEqual(traceId, 'mock_with_data');\n    });\n  });\n\n  describe.skip('mockModuleContextWithHeaders', () => {\n    beforeEach(async () => {\n      await app.mockModuleContext({\n        headers: {\n          'user-agent': 'mock_agent',\n        },\n      });\n    });\n\n    it('should mock ctx work', () => {\n      assert.strictEqual(app.currentContext.get('user-agent'), 'mock_agent');\n    });\n  });\n});\n"
  },
  {
    "path": "test/fixtures/tegg-app/tsconfig.json",
    "content": "{\n  \"extends\": \"@eggjs/tsconfig\"\n}\n"
  },
  {
    "path": "test/fixtures/tegg-app/typing.ts",
    "content": "import \"egg\";\nimport \"@eggjs/tegg-plugin\";\n"
  },
  {
    "path": "test/fixtures/test-case-create-context-failed/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/test-case-create-context-failed/package.json",
    "content": "{\n  \"name\": \"app\"\n}\n"
  },
  {
    "path": "test/fixtures/test-case-create-context-failed/test/index.test.js",
    "content": "const { setGetAppCallback } = require('../../../..');\n\nsetGetAppCallback((suite, test) => {\n  return {\n    ready: async () => {\n      // ...\n    },\n    mockContextScope: async scope => {\n      if (!test) {\n        await scope({});\n      } else {\n        throw new Error('mock create context failed');\n      }\n    },\n    backgroundTasksFinished: async () => {\n      // ...\n    },\n    close: async () => {\n      // ...\n    },\n  };\n});\n\ndescribe('test case create context error', function() {\n  it('should not print', () => {\n  });\n});\n"
  },
  {
    "path": "test/fixtures/test-case-get-app-failed/config/config.default.js",
    "content": "'use strict';\n\nmodule.exports = {\n  keys: '123',\n};\n"
  },
  {
    "path": "test/fixtures/test-case-get-app-failed/package.json",
    "content": "{\n  \"name\": \"app\"\n}\n"
  },
  {
    "path": "test/fixtures/test-case-get-app-failed/test/index.test.js",
    "content": "const { setGetAppCallback } = require('../../../..');\n\nsetGetAppCallback((suite, test) => {\n  if (test) {\n    throw new Error('mock get app failed');\n  }\n  return {\n    ready: async () => {\n      // ...\n    },\n    mockContextScope: async scope => {\n      await scope({});\n    },\n    backgroundTasksFinished: async () => {\n      // ...\n    },\n    close: async () => {\n      // ...\n    },\n  };\n});\n\ndescribe('test case get app error', () => {\n  it('should not print', () => {\n  });\n});\n"
  },
  {
    "path": "test/fixtures/yadan_app/config/config.default.js",
    "content": "'use strict';\n\nexports.keys = '123';\n"
  },
  {
    "path": "test/fixtures/yadan_app/package.json",
    "content": "{\n  \"name\": \"custom\",\n  \"egg\": {\n    \"framework\": \"yadan\"\n  }\n}\n"
  },
  {
    "path": "test/format_options.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\nconst formatOptions = require('../lib/format_options');\n\ndescribe('test/format_options.test.js', () => {\n  afterEach(mm.restore);\n\n  it('should return the default options', () => {\n    const options = formatOptions();\n    assert(options);\n    assert(options.coverage === true);\n    assert(options.cache === true);\n    assert(options.baseDir === process.cwd());\n    assert.deepEqual(options.plugins['egg-mock'], {\n      enable: true,\n      path: path.join(__dirname, '..'),\n    });\n  });\n\n  it('should return baseDir when on windows', () => {\n    const baseDir = 'D:\\\\projectWorkSpace\\\\summer';\n    mm(path, 'isAbsolute', path.win32.isAbsolute);\n    mm(process, 'cwd', () => baseDir);\n    try {\n      formatOptions();\n      throw new Error('should not run');\n    } catch (err) {\n      assert(/D:[\\\\|\\/]projectWorkSpace[\\\\|\\/]summer/.test(err.message));\n    }\n  });\n\n  it('should set cache', () => {\n    const options = formatOptions({ cache: false });\n    assert(options);\n    assert(options.cache === false);\n  });\n\n  it('should disable cache when call mm.env', () => {\n    mm.env('prod');\n    const options = formatOptions();\n    assert(options);\n    assert(options.cache === false);\n  });\n\n  it('should set coverage', () => {\n    const options = formatOptions({ coverage: false });\n    assert(options);\n    assert(options.coverage === false);\n  });\n\n  it('should return options when set full baseDir', () => {\n    const baseDir = path.join(__dirname, 'fixtures/app');\n    const options = formatOptions({ baseDir });\n    assert(options);\n    assert(options.baseDir === baseDir);\n  });\n\n  it('should return options when set short baseDir', () => {\n    const options = formatOptions({ baseDir: 'apps/foo' });\n    assert(options);\n    assert(options.baseDir === path.join(__dirname, 'fixtures/apps/foo'));\n  });\n\n  it('should return options when set customEgg', () => {\n    const customEgg = path.join(__dirname, 'fixtures/bar');\n    const options = formatOptions({ customEgg });\n    assert(options);\n    assert(options.customEgg === customEgg);\n  });\n\n  it('should return options when set customEgg=true', () => {\n    const baseDir = path.join(__dirname, 'fixtures/bar');\n    mm(process, 'cwd', () => {\n      return baseDir;\n    });\n    const options = formatOptions({ customEgg: true });\n    assert(options);\n    assert(options.customEgg === baseDir);\n  });\n\n  it('should push plugins when in plugin dir', () => {\n    const baseDir = path.join(__dirname, 'fixtures/plugin');\n    mm(process, 'cwd', () => {\n      return baseDir;\n    });\n    const options = formatOptions();\n    assert(options);\n    assert.deepEqual(options.plugins.plugin1, {\n      enable: true,\n      path: baseDir,\n    });\n  });\n\n  it('should not push pluings when in plugin dir but options.plugin = false', () => {\n    const baseDir = path.join(__dirname, 'fixtures/plugin');\n    mm(process, 'cwd', () => {\n      return baseDir;\n    });\n    const options = formatOptions({\n      plugin: false,\n    });\n    assert(options);\n    assert(!options.plugins.plugin1);\n  });\n\n  it('should not throw when no eggPlugin', () => {\n    const baseDir = path.join(__dirname, 'fixtures/plugin_throw');\n    mm(process, 'cwd', () => {\n      return baseDir;\n    });\n    formatOptions();\n  });\n\n  it('should throw when no eggPlugin and options.plugin === true', () => {\n    const baseDir = path.join(__dirname, 'fixtures/plugin_throw');\n    mm(process, 'cwd', () => {\n      return baseDir;\n    });\n    assert.throws(() => {\n      formatOptions({\n        plugin: true,\n      });\n    }, new RegExp(`should set eggPlugin in ${baseDir}/package.json`));\n  });\n\n  it('should mock process.env.HOME when EGG_SERVER_ENV is default, test, prod', () => {\n    const baseDir = process.cwd();\n\n    mm(process.env, 'EGG_SERVER_ENV', 'local');\n    assert.notEqual(process.env.HOME, baseDir);\n\n    mm(process.env, 'EGG_SERVER_ENV', 'default');\n    formatOptions();\n    assert.equal(process.env.HOME, baseDir);\n\n    mm(process.env, 'EGG_SERVER_ENV', 'test');\n    formatOptions();\n    assert.equal(process.env.HOME, baseDir);\n\n    mm(process.env, 'EGG_SERVER_ENV', 'prod');\n    formatOptions();\n    assert.equal(process.env.HOME, baseDir);\n  });\n\n  it('should not mock process.env.HOME when it has mocked', () => {\n    const baseDir = process.cwd();\n    mm(process.env, 'HOME', '/mockpath');\n    mm(process.env, 'EGG_SERVER_ENV', 'default');\n    formatOptions();\n    assert.notEqual(process.env.HOME, baseDir);\n  });\n});\n"
  },
  {
    "path": "test/index.test.ts",
    "content": "import mm from '../index';\nimport * as path from 'path';\nconst fixtures = path.join(__dirname, 'fixtures');\n\nconst app = mm.app({\n  baseDir: path.join(fixtures, 'demo'),\n});\napp.ready().then(() => {\n  app.httpRequest()\n  app.mockContext({\n    user: { name: 'Jason' }\n  });\n\n  app.mockCookies({\n    foo: 'bar'\n  });\n\n  app.mockSession({\n    foo: 'bar'\n  });\n\n  app.mockContext();\n\n  app.mockService('foo', 'get', function* (ctx, methodName, args) {\n    return 'popomore';\n  });\n\n  app.mockServiceError('foo', 'get', new Error('mock error'));\n\n  app.mockCsrf();\n\n  app.mockHttpclient('https://eggjs.org', 'mock egg');\n  app.mockHttpclient('https://eggjs.org', {\n    data: 'mock egg',\n    status: 200,\n  });\n\n  app.mockHttpclient('https://eggjs.org', [ 'get' , 'head' ], { data: 'foo' });\n\n  app.mockHttpclient('https://eggjs.org', '*', { data: 'bar' });\n\n  app.mockHttpclient('https://eggjs.org', () => ({\n    data: 'mock egg',\n    status: 200,\n  }));\n\n  app.mockHttpclient('https://eggjs.org', function (url, opts) {\n    url.toLowerCase();\n    opts.data;\n    return 'a';\n  });\n\n  app.httpRequest().post('/user').set('a', 'b').send().expect(200);\n\n  console.log('   ts run ok');\n  app.close();\n  mm.restore();\n  process.exit(0);\n}).catch(e => {\n  console.log(e);\n  process.exit(1);\n});\n\nmm.consoleLevel('INFO');\n\nmm.home('a')\n\n// mm.cluster();\n\nmm.env('test');\n\n// test for bootstrap\n(global as any).before = () => {};\n(global as any).afterEach = () => {};\n\nimport { mock, app as bootApp, assert } from '../bootstrap';\nbootApp.ready;\nmock.restore;\nassert(true);\nmock.app;\n"
  },
  {
    "path": "test/inject_ctx.test.js",
    "content": "const coffee = require('coffee');\nconst path = require('path');\n\ndescribe('test/inject_ctx.test.js', () => {\n  const eggBinFile = require.resolve('egg-bin//dist/bin/cli');\n\n  it('should inject ctx to runner', async () => {\n    const fixture = path.join(__dirname, 'fixtures/tegg-app');\n\n    await coffee.fork(eggBinFile, [\n      'test',\n      '-r', require.resolve('../register'),\n    ], {\n      cwd: fixture,\n      env: {\n        EGG_FRAMEWORK: require.resolve('egg'),\n      },\n    })\n      // .debug()\n      .expect('code', 0)\n      .expect('stdout', /\\d+ passing/)\n      .end();\n  });\n\n  it('should inject ctx to runner with setGetAppCallback', async () => {\n    const fixture = path.join(__dirname, 'fixtures/setup-app');\n\n    await coffee.fork(eggBinFile, [\n      'test',\n      '-r', require.resolve('../register'),\n    ], {\n      cwd: fixture,\n    })\n      // .debug()\n      .expect('code', 0)\n      // .expect('stdout', /9 passing/)\n      .end();\n  });\n\n  it('hook/case error should failed', async () => {\n    const fixture = path.join(__dirname, 'fixtures/failed-app');\n\n    await coffee.fork(eggBinFile, [\n      'test',\n      '-r', require.resolve('../register'),\n    ], {\n      cwd: fixture,\n      env: {\n        EGG_FRAMEWORK: require.resolve('egg'),\n      },\n    })\n      // .debug()\n      .expect('stdout', /after error test case should print/)\n      .expect('stdout', /afterEach error test case should print/)\n      .expect('stdout', /\"before all\" hook for \"should not print\"/)\n      .expect('stdout', /\"after all\" hook for \"should print\"/)\n      .expect('stdout', /\"before each\" hook for \"should not print\"/)\n      .expect('stdout', /\"after each\" hook for \"should print\"/)\n      .expect('stdout', /3 passing/)\n      // 1 after + 1 afterEach + 1 before + 1 beforeEach + 1 test case\n      .expect('stdout', /5 failing/)\n      .expect('code', 1)\n      .end();\n  });\n\n  describe('run suite', () => {\n    //   test/inject_ctx.test.js\n    //     run suite\n    //   1) \"before all\" hook: beforeAll in \"{root}\"\n    //   2) \"after all\" hook: afterAll in \"{root}\"\n    //   0 passing (7ms)\n    //   2 failing\n    //   1) \"before all\" hook: beforeAll in \"{root}\":\n    //      Error: mock get app failed\n    //   2) \"after all\" hook: afterAll in \"{root}\":\n    //      Error: mock get app failed\n    it('get app error should failed', async () => {\n      const fixture = path.join(__dirname, 'fixtures/get-app-failed');\n\n      await coffee.fork(eggBinFile, [\n        'test',\n        '-r', require.resolve('../register'),\n      ], {\n        cwd: fixture,\n        env: {\n          EGG_FRAMEWORK: require.resolve('egg'),\n        },\n      })\n        // .debug()\n        .expect('code', 1)\n        .expect('stdout', /\"before all\" hook: beforeAll in \"{root}\"/)\n        .end();\n    });\n\n    //   test/inject_ctx.test.js\n    //     run suite\n    //   1) \"before all\" hook: egg-mock-mock-ctx-failed in \"{root}\"\n    //   0 passing (4ms)\n    //   1 failing\n    //   1) \"before all\" hook: egg-mock-mock-ctx-failed in \"{root}\":\n    //      Error: mock create context failed\n    it('create context error should failed', async () => {\n      const fixture = path.join(__dirname, 'fixtures/create-context-failed');\n\n      await coffee.fork(eggBinFile, [\n        'test',\n        '-r', require.resolve('../register'),\n      ], {\n        cwd: fixture,\n        env: {\n          EGG_FRAMEWORK: require.resolve('egg'),\n        },\n      })\n        // .debug()\n        .expect('code', 1)\n        .expect('stdout', /Error: mock create context failed/)\n        .end();\n    });\n\n    //   1) \"before all\" hook: beforeAll in \"{root}\"\n    //   2) \"after all\" hook: afterAll in \"{root}\"\n    //   0 passing (432ms)\n    //   2 failing\n    //   1) \"before all\" hook: beforeAll in \"{root}\":\n    //      Error: mock app ready failed\n    //   2) \"after all\" hook: afterAll in \"{root}\":\n    //      Error: mock app ready failed\n    it('app.ready error should failed', async () => {\n      const fixture = path.join(__dirname, 'fixtures/app-ready-failed');\n\n      await coffee.fork(eggBinFile, [\n        'test',\n        '-r', require.resolve('../register'),\n      ], {\n        cwd: fixture,\n        env: {\n          EGG_FRAMEWORK: require.resolve('egg'),\n        },\n      })\n        // .debug()\n        .expect('code', 1)\n        .expect('stdout', /mock app ready failed/)\n        .end();\n    });\n  });\n\n  describe('run test', () => {\n    //  test case get app error\n    //     1) should not print\n    //   0 passing (5ms)\n    //   1 failing\n    //   1) test case get app error\n    //        should not print:\n    //      Error: mock get app failed\n    it('get app error should failed', async () => {\n      const fixture = path.join(__dirname, 'fixtures/test-case-get-app-failed');\n\n      await coffee.fork(eggBinFile, [\n        'test',\n        '-r', require.resolve('../register'),\n      ], {\n        cwd: fixture,\n        env: {\n          EGG_FRAMEWORK: require.resolve('egg'),\n        },\n      })\n        // .debug()\n        .expect('code', 1)\n        .expect('stdout', /Error: mock get app failed/)\n        .end();\n    });\n\n    //   test case create context error\n    //     1) should not print\n    //   0 passing (7ms)\n    //   1 failing\n    //   1) test case create context error\n    //        should not print:\n    //      Error: mock create context failed\n    //       at Object.mockContextScope (test/index.test.js:12:15)\n    //       at next (/Users/killa/workspace/egg-mock/lib/inject_context.js:107:30)\n    it('create context error should failed', async () => {\n      const fixture = path.join(__dirname, 'fixtures/test-case-create-context-failed');\n\n      await coffee.fork(eggBinFile, [\n        'test',\n        '-r', require.resolve('../register'),\n      ], {\n        cwd: fixture,\n        env: {\n          EGG_FRAMEWORK: require.resolve('egg'),\n        },\n      })\n        // .debug()\n        .expect('code', 1)\n        .expect('stdout', /Error: mock create context failed/)\n        .end();\n    });\n  });\n});\n"
  },
  {
    "path": "test/mm.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst fs = require('fs');\nconst assert = require('assert');\nconst mm = require('..');\n\nconst baseDir = path.join(__dirname, 'fixtures/apps/env-app');\n\ndescribe('test/mm.test.js', () => {\n\n  afterEach(mm.restore);\n\n  describe('mm.env()', () => {\n\n    let app;\n    beforeEach(() => {\n      mm(process.env, 'EGG_HOME', baseDir);\n    });\n    afterEach(() => app.close());\n\n    it('should mock unittest', async () => {\n      app = mm.app({ baseDir: 'apps/env-app', cache: false });\n      await app.ready();\n      assert(app.config.fakeplugin.foo === 'bar-unittest');\n      assert(app.config.logger.dir === path.join(baseDir, 'logs/env-app'));\n    });\n\n    it('should mock test', async () => {\n      mm.env('test');\n      app = mm.app({ baseDir: 'apps/env-app', cache: false });\n      await app.ready();\n      assert(app.config.fakeplugin.foo === 'bar-test');\n      assert(app.config.logger.dir === path.join(baseDir, 'logs/env-app'));\n    });\n\n    it('should mock prod', async () => {\n      mm.env('prod');\n      app = mm.app({ baseDir: 'apps/env-app', cache: false });\n      await app.ready();\n      assert(app.config.fakeplugin.foo === 'bar-prod');\n      assert(app.config.logger.dir === path.join(baseDir, 'logs/env-app'));\n    });\n\n    it('should mock default', async () => {\n      mm.env('default');\n      app = mm.app({ baseDir: 'apps/env-app', cache: false });\n      await app.ready();\n      assert(app.config.fakeplugin.foo === 'bar-default');\n      assert(app.config.logger.dir === path.join(baseDir, 'logs/env-app'));\n    });\n\n    it('should mock unittest', async () => {\n      mm.env('unittest');\n      app = mm.app({ baseDir: 'apps/env-app', cache: false });\n      await app.ready();\n      assert(app.config.fakeplugin.foo === 'bar-unittest');\n      assert(app.config.logger.dir === path.join(baseDir, 'logs/env-app'));\n    });\n\n    it('should mock local', async () => {\n      mm.env('local');\n      app = mm.app({ baseDir: 'apps/env-app', cache: false });\n      await app.ready();\n      assert(app.config.fakeplugin.foo === 'bar-default');\n      assert(app.config.logger.dir === path.join(baseDir, 'logs/env-app'));\n    });\n  });\n\n  describe('mm.app({ clean: false })', () => {\n    let app;\n    after(() => app.close());\n\n    it('keep log dir', async () => {\n      app = mm.app({ baseDir: 'apps/app-not-clean', clean: false });\n      await app.ready();\n      assert(fs.existsSync(path.join(__dirname, 'fixtures/apps/app-not-clean/logs/keep')));\n    });\n  });\n\n  describe('mm.consoleLevel()', () => {\n    it('shoud mock EGG_LOG', () => {\n      mm.consoleLevel('none');\n      assert(process.env.EGG_LOG === 'NONE');\n    });\n\n    it('shoud not mock', () => {\n      mm.consoleLevel('');\n      assert(!process.env.EGG_LOG);\n    });\n  });\n\n  describe('mm.home', () => {\n    let app;\n    const baseDir = path.join(__dirname, 'fixtures/apps/mockhome');\n    before(() => {\n      mm.home(baseDir);\n      app = mm.app({ baseDir: 'apps/mockhome', clean: false });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should mock home', () => {\n      assert(app.config.HOME === baseDir);\n    });\n\n    it('should ignore when parameter is empty', () => {\n      mm.home();\n      assert(!process.env.EGG_HOME);\n    });\n  });\n\n  describe('egg-mock', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir: 'apps/no-framework',\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should not be a framework', () => {\n      app.mockEnv();\n      assert(app.config.env === 'mocked by plugin');\n    });\n  });\n});\n"
  },
  {
    "path": "test/mock_agent_httpclient.test.js",
    "content": "'use strict';\n\nconst pedding = require('pedding');\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\nconst fixtures = path.join(__dirname, 'fixtures');\n\nconst url = 'http://127.0.0.1:9989/mock_url';\n\ndescribe('test/mock_agent_httpclient.test.js', () => {\n  let app;\n  let agent;\n  let httpclient;\n  before(() => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo'),\n    });\n    return app.ready();\n  });\n  before(() => {\n    agent = app.agent;\n    httpclient = crtHttpclient(agent);\n  });\n  after(() => app.agent.close());\n  afterEach(mm.restore);\n\n  it('should mock url and get reponse event on urllib', done => {\n    done = pedding(3, done);\n    agent.mockHttpclient(url, {\n      data: Buffer.from('mock response'),\n    });\n\n    agent.httpclient.once('request', function(meta) {\n      assert('url' in meta);\n      assert('args' in meta);\n      done();\n    });\n\n    agent.httpclient.once('response', function(result) {\n      assert('url' in result.req);\n      assert('size' in result.req);\n      assert('options' in result.req);\n\n      assert.deepEqual(result.res, {\n        status: 200,\n        statusCode: 200,\n        headers: {},\n        size: 13,\n        aborted: false,\n        rt: 1,\n        keepAliveSocket: false,\n      });\n      done();\n    });\n\n    let count = 0;\n    agent.httpclient.on('response', function(result) {\n      if (count === 0) {\n        assert.deepEqual(result.req.options, {\n          dataType: undefined,\n          method: 'GET',\n          headers: {},\n        });\n      } else if (count === 1) {\n        assert.deepEqual(result.req.options, {\n          dataType: undefined,\n          method: 'POST',\n          headers: {\n            'x-custom': 'custom',\n          },\n        });\n      }\n      count++;\n    });\n\n    httpclient()\n      .then(data => {\n        assert.deepEqual(data, {\n          get: 'mock response',\n          post: 'mock response',\n        });\n        done();\n      });\n  });\n\n  it('should mock url support multi method', done => {\n    done = pedding(2, done);\n    agent.mockHttpclient(url, [ 'get', 'post' ], {\n      data: Buffer.from('mock response'),\n    });\n\n    agent.httpclient.once('response', function(result) {\n      assert.deepEqual(result.res, {\n        status: 200,\n        statusCode: 200,\n        headers: {},\n        size: 13,\n        aborted: false,\n        rt: 1,\n        keepAliveSocket: false,\n      });\n      done();\n    });\n\n    httpclient()\n      .then(data => {\n        assert.deepEqual(data, {\n          get: 'mock response',\n          post: 'mock response',\n        });\n        done();\n      });\n  });\n\n  it('should mock url method support *', done => {\n    done = pedding(2, done);\n    agent.mockHttpclient(url, '*', {\n      data: Buffer.from('mock response'),\n    });\n\n    agent.httpclient.once('response', function(result) {\n      assert.deepEqual(result.res, {\n        status: 200,\n        statusCode: 200,\n        headers: {},\n        size: 13,\n        aborted: false,\n        rt: 1,\n        keepAliveSocket: false,\n      });\n      done();\n    });\n\n    httpclient()\n      .then(data => {\n        assert.deepEqual(data, {\n          get: 'mock response',\n          post: 'mock response',\n        });\n        done();\n      });\n  });\n\n  it('should mock url get and post', done => {\n    agent.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n    agent.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n\n    httpclient()\n      .then(data => {\n        assert.deepEqual(data, {\n          get: 'mock url get',\n          post: 'mock url post',\n        });\n        done();\n      });\n  });\n\n  it('should support request', done => {\n    agent.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n    agent.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n\n    httpclient('request')\n      .then(data => {\n        assert.deepEqual(data, {\n          get: 'mock url get',\n          post: 'mock url post',\n        });\n        done();\n      });\n  });\n\n  it('should support curl', done => {\n    agent.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n    agent.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n\n    httpclient('curl')\n      .then(data => {\n        assert.deepEqual(data, {\n          get: 'mock url get',\n          post: 'mock url post',\n        });\n        done();\n      });\n  });\n\n  it('should support json', done => {\n    agent.mockHttpclient(url, {\n      data: { method: 'get' },\n    });\n    agent.mockHttpclient(url, 'post', {\n      data: { method: 'post' },\n    });\n\n    httpclient('request', 'json')\n      .then(data => {\n        assert.deepEqual(data, {\n          get: { method: 'get' },\n          post: { method: 'post' },\n        });\n        done();\n      });\n  });\n\n  it('should support text', done => {\n    agent.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n    agent.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n\n    httpclient('request', 'text')\n      .then(data => {\n        assert.deepEqual(data, {\n          get: 'mock url get',\n          post: 'mock url post',\n        });\n        done();\n      });\n  });\n\n  it('should mock url and get reponse event on urllib', done => {\n    agent.mockHttpclient(url, {\n      data: Buffer.from('mock response'),\n    });\n\n    httpclient()\n      .then(data => {\n        assert.deepEqual(data, {\n          get: 'mock response',\n          post: 'mock response',\n        });\n        done();\n      });\n  });\n\n});\n\nfunction crtHttpclient(app) {\n  return (method = 'request', dataType) => {\n    const r1 = app.httpclient[method](url, {\n      dataType,\n    });\n\n    const r2 = app.httpclient[method](url, {\n      method: 'POST',\n      dataType,\n      headers: {\n        'x-custom': 'custom',\n      },\n    });\n    return Promise.all([ r1, r2 ]).then(([ r1, r2 ]) => {\n      return {\n        get: Buffer.isBuffer(r1.data) ? r1.data.toString() : r1.data,\n        post: Buffer.isBuffer(r2.data) ? r2.data.toString() : r2.data,\n      };\n    });\n  };\n}\n\n"
  },
  {
    "path": "test/mock_cluster_extend.test.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst mm = require('..');\n\ndescribe('test/mock_cluster_extend.test.js', () => {\n  let app;\n  before(() => {\n    app = mm.cluster({\n      baseDir: 'demo',\n      coverage: false,\n    });\n    return app.ready();\n  });\n  after(() => app.close());\n\n  afterEach(mm.restore);\n\n  it('should mock cluster with result', function* () {\n    let result = yield app.mockDevice({ name: 'egg' });\n    assert.deepEqual(result, { name: 'egg', mock: true });\n\n    result = yield app.mockGenerator({ name: 'egg generator' });\n    assert.deepEqual(result, { name: 'egg generator', mock: true });\n\n    result = yield app.mockPromise({ name: 'egg promise' });\n    assert.deepEqual(result, { name: 'egg promise', mock: true });\n  });\n});\n"
  },
  {
    "path": "test/mock_cluster_restore.test.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst fs = require('fs');\nconst path = require('path');\nconst { sleep } = require('../lib/utils');\nconst mm = require('..');\n\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_cluster_restore.test.js', () => {\n  let app;\n  before(() => {\n    app = mm.cluster({\n      baseDir: 'demo',\n      coverage: false,\n    });\n    return app.ready();\n  });\n  after(() => app.close());\n\n  afterEach(mm.restore);\n\n  it('should mock cluster restore work', function* () {\n    app.mockSession({\n      user: {\n        foo: 'bar',\n      },\n      hello: 'egg mock session data',\n    });\n    yield app.httpRequest()\n      .get('/session')\n      .expect({\n        user: {\n          foo: 'bar',\n        },\n        hello: 'egg mock session data',\n      });\n\n    mm.restore();\n    yield app.httpRequest()\n      .get('/session')\n      .expect({});\n  });\n\n  describe('handle uncaughtException', () => {\n    let app;\n    before(() => {\n      app = mm.cluster({\n        baseDir: 'apps/app-throw',\n        coverage: false,\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should handle uncaughtException and log it', function* () {\n      yield app.httpRequest()\n        .get('/throw')\n        .expect('foo')\n        .expect(200);\n\n      yield sleep(1100);\n      const logfile = path.join(fixtures, 'apps/app-throw/logs/app-throw/common-error.log');\n      const body = fs.readFileSync(logfile, 'utf8');\n      assert(body.includes('ReferenceError: a is not defined (uncaughtException throw'));\n    });\n  });\n});\n"
  },
  {
    "path": "test/mock_cluster_without_security_plugin.test.js",
    "content": "'use strict';\n\nconst mm = require('..');\n\ndescribe('test/mock_cluster_without_security.test.js', () => {\n  let app;\n  before(() => {\n    app = mm.cluster({\n      baseDir: 'disable-security',\n      coverage: false,\n    });\n    return app.ready();\n  });\n  after(() => app.close());\n\n  afterEach(mm.restore);\n\n  it('should mock cluster work', () => {\n    app.mockSession({\n      user: {\n        foo: 'bar',\n      },\n      hello: 'egg mock session data',\n    });\n    return app.httpRequest()\n      .get('/session')\n      .expect({\n        user: {\n          foo: 'bar',\n        },\n        hello: 'egg mock session data',\n      });\n  });\n});\n"
  },
  {
    "path": "test/mock_context.test.js",
    "content": "const assert = require('assert');\nconst mm = require('..');\n\ndescribe('test/mock_context.test.js', () => {\n  let app;\n  before(done => {\n    app = mm.app({\n      baseDir: 'demo',\n    });\n    app.ready(done);\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should work on GET with user login', () => {\n    app.mockContext({\n      user: {\n        foo: 'bar',\n      },\n      tracer: {\n        traceId: 'foo-traceId',\n      },\n    });\n\n    // assert(ctx.user.foo === 'bar');\n    return app.httpRequest()\n      .get('/user')\n      .expect(200)\n      .expect({\n        foo: 'bar',\n      })\n      .expect('x-request-url', '/user');\n  });\n\n  it('should work on POST with user login', () => {\n    app.mockContext({\n      user: {\n        foo: 'bar',\n      },\n    });\n\n    app.mockCsrf();\n    return app.httpRequest()\n      .post('/user')\n      .send({\n        hi: 'body',\n        a: 123,\n      })\n      .expect(200)\n      .expect({\n        params: {\n          hi: 'body',\n          a: 123,\n        },\n        user: {\n          foo: 'bar',\n        },\n      });\n  });\n\n  it.skip('should work on POST file with user login', async () => {\n    const ctx = app.mockContext({\n      user: {\n        foo: 'bar',\n      },\n      traceId: `trace-${Date.now}`,\n    });\n    // assert(ctx.user.foo === 'bar');\n    const ctxFromStorage = app.ctxStorage.getStore();\n    assert(ctxFromStorage === ctx);\n    assert(app.currentContext === ctx);\n\n    app.mockCsrf();\n    await app.httpRequest()\n      .post('/file')\n      .field('title', 'file title')\n      .attach('file', __filename)\n      .expect(200)\n      .expect({\n        fields: {\n          title: 'file title',\n        },\n        filename: 'mock_context.test.js',\n        user: {\n          foo: 'bar',\n        },\n        traceId: ctx.traceId,\n        ctxFromStorageUser: ctxFromStorage.user,\n        ctxFromStorageTraceId: ctxFromStorage.traceId,\n      });\n    const ctxFromStorage2 = app.ctxStorage.getStore();\n    assert(ctxFromStorage2 === ctx);\n    mm.restore();\n    const ctxFromStorage3 = app.ctxStorage.getStore();\n    assert(!ctxFromStorage3);\n    assert(!app.currentContext);\n  });\n});\n"
  },
  {
    "path": "test/mock_cookies.test.js",
    "content": "'use strict';\n\nconst request = require('supertest');\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_cookies.test.js', () => {\n  let app;\n  before(done => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'apps/mock_cookies'),\n    });\n    app.ready(done);\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should not return when don\\'t mock cookies', done => {\n    const ctx = app.mockContext();\n    assert(!ctx.cookies.get('foo'));\n\n    request(app.callback())\n      .get('/')\n      .expect(function(res) {\n        assert.deepEqual(res.body, {});\n      })\n      .expect(200, done);\n  });\n\n  it('should mock cookies', done => {\n    app.mockCookies({\n      foo: 'bar cookie',\n    });\n    // const ctx = app.mockContext();\n    // assert(ctx.cookies.get('foo') === 'bar cookie');\n\n    request(app.callback())\n      .get('/')\n      .expect({\n        cookieValue: 'bar cookie',\n        cookiesValue: 'bar cookie',\n      })\n      .expect(200, done);\n  });\n\n  it('should pass cookie opt', done => {\n    app.mockCookies({});\n\n    request(app.callback())\n      .get('/')\n      .set('cookie', 'foo=bar cookie')\n      .expect({\n        cookieValue: 'bar cookie',\n        cookiesValue: 'bar cookie',\n      })\n      .expect(200, done);\n  });\n\n});\n"
  },
  {
    "path": "test/mock_csrf.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst request = require('supertest');\nconst mm = require('..');\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_csrf.test.js', () => {\n\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo'),\n    });\n    return app.ready();\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should work', done => {\n    app.mockCsrf();\n    request(app.callback())\n      .post('/')\n      .expect(200)\n      .expect('done', done);\n  });\n});\n"
  },
  {
    "path": "test/mock_custom_loader.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_custom_loader.test.js', () => {\n  let app;\n  before(async () => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'custom-loader'),\n    });\n    await app.ready();\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should return success', async () => {\n    await app.httpRequest()\n      .get('/users/popomore')\n      .expect({\n        adapter: 'docker',\n        repository: 'popomore',\n      })\n      .expect(200);\n  });\n\n  it('should return when mock with data', async () => {\n    app.mockRepository('user', 'get', 'mock');\n    app.mockAdapter('docker', 'inspectDocker', 'mock');\n    await app.httpRequest()\n      .get('/users/popomore')\n      .expect({\n        adapter: 'mock',\n        repository: 'mock',\n      })\n      .expect(200);\n  });\n\n  it('should return when mock the instance', async () => {\n    app.mockAdapter(app.adapter.docker, 'inspectDocker', 'mock');\n    await app.httpRequest()\n      .get('/users/popomore')\n      .expect({\n        adapter: 'mock',\n        repository: 'popomore',\n      })\n      .expect(200);\n  });\n\n  it('should not override the existing API', () => {\n    assert(app.mockEnv === require('../app/extend/application.js').mockEnv);\n  });\n});\n"
  },
  {
    "path": "test/mock_env.test.js",
    "content": "const path = require('node:path');\nconst { strict: assert } = require('node:assert');\nconst mm = require('..');\n\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_env.test.js', () => {\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo'),\n    });\n    return app.ready();\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should mock env success', () => {\n    app.mockEnv('prod');\n    assert.equal(app.config.env, 'prod');\n    assert.equal(app.config.serverEnv, 'prod');\n  });\n\n  it('should keep mm.restore execute in the current event loop', async () => {\n    mm.restore();\n    assert.equal(app.config.env, 'unittest');\n    assert.equal(app.config.serverEnv, undefined);\n\n    app.mockEnv('prod');\n    assert.equal(app.config.env, 'prod');\n    assert.equal(app.config.serverEnv, 'prod');\n\n    await sleep(1);\n    assert.equal(app.config.env, 'prod');\n    assert.equal(app.config.serverEnv, 'prod');\n\n    mm.restore();\n    assert.equal(app.config.env, 'unittest');\n    assert.equal(app.config.serverEnv, undefined);\n  });\n});\n\nfunction sleep(ms) {\n  return new Promise(resolve => {\n    setTimeout(resolve, ms);\n  });\n}\n"
  },
  {
    "path": "test/mock_headers.test.js",
    "content": "'use strict';\n\nconst request = require('supertest');\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_headers.test.js', () => {\n\n  afterEach(mm.restore);\n\n  let app;\n  before(() => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo'),\n    });\n    return app.ready();\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should not exists without mock', done => {\n    app.mockContext();\n\n    request(app.callback())\n      .get('/header')\n      .expect(function(res) {\n        assert(res.body.header === '');\n      })\n      .expect(200, done);\n  });\n\n  it('should mock headers', done => {\n    app.mockContext();\n    app.mockHeaders({\n      customheader: 'customheader',\n    });\n    request(app.callback())\n      .get('/header')\n      .expect(function(res) {\n        assert(res.body.header === 'customheader');\n      })\n      .expect(200, done);\n  });\n\n  it('should mock headers that is uppercase', done => {\n    app.mockContext();\n    app.mockHeaders({\n      Customheader: 'customheader',\n    });\n    request(app.callback())\n      .get('/header')\n      .expect(function(res) {\n        assert(res.body.header === 'customheader');\n      })\n      .expect(200, done);\n  });\n});\n"
  },
  {
    "path": "test/mock_httpclient.test.js",
    "content": "'use strict';\n\nconst pedding = require('pedding');\nconst path = require('path');\nconst request = require('supertest');\nconst assert = require('assert');\nconst { sleep } = require('../lib/utils');\nconst mm = require('..');\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_httpclient.test.js', () => {\n  let app;\n  let server;\n  let url;\n  before(() => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo'),\n    });\n    return app.ready();\n  });\n  before(() => {\n    server = app.listen();\n    url = `http://127.0.0.1:${server.address().port}/mock_url`;\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should mock url and get reponse event on urllib', done => {\n    done = pedding(2, done);\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: Buffer.from('mock response'),\n    });\n\n    request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock response',\n        post: 'mock response',\n      })\n      .expect(200, done);\n\n    app.httpclient.once('response', function(result) {\n      assert('url' in result.req);\n      assert('size' in result.req);\n      assert('options' in result.req);\n\n      assert.deepEqual(result.res, {\n        status: 200,\n        statusCode: 200,\n        headers: {},\n        size: 13,\n        aborted: false,\n        rt: 1,\n        keepAliveSocket: false,\n      });\n      done();\n    });\n\n    let count = 0;\n    app.httpclient.on('response', function(result) {\n      if (count === 0) {\n        assert.deepEqual(result.req.options, {\n          data: undefined,\n          dataType: undefined,\n          method: 'GET',\n          headers: {},\n        });\n      } else if (count === 1) {\n        assert.deepEqual(result.req.options, {\n          data: undefined,\n          dataType: undefined,\n          method: 'POST',\n          headers: {\n            'x-custom': 'custom',\n          },\n        });\n      }\n      count++;\n    });\n  });\n\n  it('should mock url support multi method', done => {\n    done = pedding(2, done);\n    app.mockCsrf();\n    app.mockHttpclient(url, [ 'get', 'post' ], {\n      data: Buffer.from('mock response'),\n    });\n\n    request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock response',\n        post: 'mock response',\n      })\n      .expect(200, done);\n\n    app.httpclient.once('response', function(result) {\n      assert.deepEqual(result.res, {\n        status: 200,\n        statusCode: 200,\n        headers: {},\n        size: 13,\n        aborted: false,\n        rt: 1,\n        keepAliveSocket: false,\n      });\n      done();\n    });\n  });\n\n  it('should mock url method support *', done => {\n    done = pedding(2, done);\n    app.mockCsrf();\n    app.mockHttpclient(url, '*', {\n      data: Buffer.from('mock response'),\n    });\n\n    request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock response',\n        post: 'mock response',\n      })\n      .expect(200, done);\n\n    app.httpclient.once('response', function(result) {\n      assert.deepEqual(result.res, {\n        status: 200,\n        statusCode: 200,\n        headers: {},\n        size: 13,\n        aborted: false,\n        rt: 1,\n        keepAliveSocket: false,\n      });\n      done();\n    });\n  });\n\n  it('should mock url post', done => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: Buffer.from('mock url post'),\n    });\n\n    request(server)\n      .get('/urllib')\n      .expect({\n        get: 'url get',\n        post: 'mock url post',\n      })\n      .expect(200, done);\n  });\n\n  it('should mock url get and post', done => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n\n    request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200, done);\n  });\n\n  it('should support request', done => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n\n    request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200, done);\n  });\n\n  it('should support curl', done => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n\n    request(server)\n      .get('/urllib?method=curl')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200, done);\n  });\n\n  it('should support json', done => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: { method: 'get' },\n    });\n    app.mockHttpclient(url, 'post', {\n      data: { method: 'post' },\n    });\n\n    request(server)\n      .get('/urllib?dataType=json')\n      .expect({\n        get: { method: 'get' },\n        post: { method: 'post' },\n      })\n      .expect(200, done);\n  });\n\n  it('should support text', done => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n\n    request(server)\n      .get('/urllib?dataType=text')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200, done);\n  });\n\n  it('should exits req headers', done => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url test',\n    });\n    request(server)\n      .get('/mock_urllib')\n      .expect({})\n      .expect(200, done);\n  });\n\n  it('should deprecate mockUrllib', done => {\n    app.mockCsrf();\n    app.mockUrllib(url, {\n      data: 'mock url test',\n    });\n    request(server)\n      .get('/mock_urllib')\n      .expect({})\n      .expect(200, done);\n  });\n\n  it('should mock url and get reponse event on urllib', done => {\n    app.mockCsrf();\n    app.mockHttpclient(/\\/mock_url$/, {\n      data: Buffer.from('mock response'),\n    });\n\n    request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock response',\n        post: 'mock response',\n      })\n      .expect(200, done);\n  });\n\n  it('should use copy of mock data', function* () {\n    app.mockCsrf();\n    app.mockHttpclient(/\\/mock_url$/, {\n      data: { a: 1 },\n    });\n\n    yield request(server)\n      .get('/data_type')\n      .expect({\n        a: 1,\n      })\n      .expect(200);\n\n    yield request(server)\n      .get('/data_type')\n      .expect({\n        a: 1,\n      })\n      .expect(200);\n  });\n\n  it('should support fn', function* () {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'get', (url, opt) => {\n      return `mock ${url} with ${opt.data.a}`;\n    });\n    app.mockHttpclient(url, 'post', 'mock url post');\n\n    yield request(server)\n      .get('/urllib')\n      .query({ data: JSON.stringify({ a: 'b' }) })\n      .expect({\n        get: `mock ${url} with b`,\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should support async function', function* () {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'get', async (url, opt) => {\n      await sleep(100);\n      return `mock ${url} with ${opt.data.a}`;\n    });\n    app.mockHttpclient(url, 'post', 'mock url post');\n\n    yield request(server)\n      .get('/urllib')\n      .query({ data: JSON.stringify({ a: 'b' }) })\n      .expect({\n        get: `mock ${url} with b`,\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should mock fn with multi-request without error', function* () {\n    app.mockCsrf();\n    let i = 0;\n    app.mockHttpclient(url, 'post', () => {\n      i++;\n      return {};\n    });\n\n    yield request(server).get('/urllib').expect(200);\n    yield request(server).get('/urllib').expect(200);\n    yield request(server).get('/urllib').expect(200);\n    assert(i === 3);\n  });\n});\n"
  },
  {
    "path": "test/mock_httpclient_next.test.js",
    "content": "const pedding = require('pedding');\nconst path = require('path');\nconst fs = require('fs');\nconst request = require('supertest');\nconst assert = require('assert');\nconst { sleep } = require('../lib/utils');\nconst mm = require('..');\n\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_httpclient_next.test.js', () => {\n  let app;\n  let server;\n  let url;\n  let url2;\n  before(() => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo_next'),\n    });\n    return app.ready();\n  });\n  before(() => {\n    server = app.listen();\n    url = `http://127.0.0.1:${server.address().port}/mock_url`;\n    url2 = `http://127.0.0.1:${server.address().port}/mock_url2`;\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should mock url and get reponse event on urllib', done => {\n    done = pedding(2, done);\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: Buffer.from('mock all response'),\n    });\n\n    request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock all response',\n        post: 'mock all response',\n      })\n      .expect(200, done);\n\n    app.httpclient.once('response', result => {\n      assert('url' in result.req);\n      // assert('size' in result.req);\n      assert('options' in result.req);\n\n      assert(result.res.status === 200);\n      assert(result.res.statusCode === 200);\n      assert.deepEqual(result.res.headers, {});\n      assert(result.res.rt);\n      done();\n    });\n\n    let count = 0;\n    app.httpclient.on('response', result => {\n      if (count === 0) {\n        const options = result.req.options;\n        assert(options.method === 'GET');\n      } else if (count === 1) {\n        const options = result.req.options;\n        assert(options.method === 'POST');\n        assert(options.headers['x-custom'] === 'custom');\n      }\n      count++;\n    });\n  });\n\n  it('should mock url using app.mockAgent().intercept()', async () => {\n    app.mockCsrf();\n    app.mockAgent()\n      .get(new URL(url).origin)\n      .intercept({\n        path: '/mock_url',\n        method: 'GET',\n      })\n      .reply(200, 'mock GET response');\n    app.mockAgent()\n      .get(new URL(url).origin)\n      .intercept({\n        path: '/mock_url',\n        method: 'POST',\n      })\n      .reply(200, 'mock POST response');\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock GET response',\n        post: 'mock POST response',\n      })\n      .expect(200);\n  });\n\n  it('should support on streaming', async () => {\n    app.mockHttpclient(url, 'get', {\n      data: fs.readFileSync(__filename),\n    });\n\n    const res = await request(server)\n      .get('/streaming')\n      .expect(200);\n    assert.match(res.body.toString(), /should support on streaming/);\n    assert.equal(res.body.toString(), fs.readFileSync(__filename, 'utf8'));\n  });\n\n  it('should mock url support multi method', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, [ 'get', 'post' ], {\n      data: Buffer.from('mock response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock response',\n        post: 'mock response',\n      })\n      .expect(200);\n  });\n\n  it('should mockHttpclient call multi times work with Regex', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(/\\/not\\/match\\//, {\n      data: Buffer.from('mock not match response'),\n    });\n    app.mockHttpclient(/\\/mock_url/, {\n      data: Buffer.from('mock 1 match response'),\n    });\n    app.mockHttpclient(/\\/mock_url/, {\n      data: Buffer.from('mock 2 match response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock 1 match response',\n        post: 'mock 1 match response',\n      })\n      .expect(200);\n  });\n\n  it('should mockHttpclient call multi times work with url string', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(`${url}-not-match`, {\n      data: Buffer.from('mock not match response'),\n    });\n    app.mockHttpclient(url, {\n      data: Buffer.from('mock 1 match response'),\n    });\n    app.mockHttpclient(url, {\n      data: Buffer.from('mock 2 match response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock 1 match response',\n        post: 'mock 1 match response',\n      })\n      .expect(200);\n  });\n\n  it('should mock url method support *', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, '*', {\n      data: Buffer.from('mock * response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock * response',\n        post: 'mock * response',\n      })\n      .expect(200);\n  });\n\n  it('should mock url post', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: Buffer.from('mock url post'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should use first mock data on duplicate url mock', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: Buffer.from('mock url1 first post'),\n    });\n    // should ignore this same url mock data, use the first mock data\n    app.mockHttpclient(url, 'post', {\n      data: Buffer.from('mock url1 second post'),\n    });\n    app.mockHttpclient(url2, 'post', {\n      data: Buffer.from('mock url2 post'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'url get',\n        post: 'mock url1 first post',\n      })\n      .expect(200);\n    await request(server)\n      .get('/urllib')\n      .query({\n        mock_url: '/mock_url2',\n      })\n      .expect({\n        get: 'url get',\n        post: 'mock url2 post',\n      })\n      .expect(200);\n  });\n\n  it('should mock work on query', async () => {\n    app.mockCsrf();\n    // mockHttpclient not support query, should use mockAgent instead\n    app.mockHttpclient(`${url}?foo=foo1`, 'get', {\n      data: Buffer.from('mock foo1'),\n    });\n    app.mockHttpclient(`${url}?foo=foo2`, 'get', {\n      data: Buffer.from('mock foo1'),\n    });\n    await request(server)\n      .get('/urllib')\n      .query({ foo: 'foo1' })\n      .expect({\n        get: 'mock foo1',\n        post: 'url post',\n      })\n      .expect(200);\n    await request(server)\n      .get('/urllib')\n      .query({ foo: 'foo2' })\n      .expect({\n        get: 'mock foo1',\n        post: 'url post',\n      })\n      .expect(200);\n    await app.mockAgentRestore();\n\n    app.mockAgent().get(new URL(url).origin)\n      .intercept({\n        path: '/mock_url?foo=foo1',\n        method: 'GET',\n      })\n      .reply(200, 'mock new foo1');\n    app.mockAgent().get(new URL(url).origin)\n      .intercept({\n        path: '/mock_url?foo=foo2',\n        method: 'GET',\n      })\n      .reply(200, 'mock new foo2');\n    await request(server)\n      .get('/urllib')\n      .query({ foo: 'foo1' })\n      .expect({\n        get: 'mock new foo1',\n        post: 'url post',\n      })\n      .expect(200);\n    await request(server)\n      .get('/urllib')\n      .query({ foo: 'foo2' })\n      .expect({\n        get: 'mock new foo2',\n        post: 'url post',\n      })\n      .expect(200);\n  });\n\n  it('should mock url get and post', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should support request', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should support persist = false', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url',\n      persist: false,\n    });\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'mock url',\n        post: 'url post',\n      })\n      .expect(200);\n  });\n\n  it('should support persist = true and ignore repeats = 1', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url',\n      persist: true,\n      repeats: 1,\n    });\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'mock url',\n        post: 'mock url',\n      })\n      .expect(200);\n  });\n\n  it('should support persist = false and repeats = 2', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url',\n      delay: 100,\n      persist: false,\n      repeats: 2,\n    });\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'mock url',\n        post: 'mock url',\n      })\n      .expect(200);\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'url get',\n        post: 'url post',\n      })\n      .expect(200);\n  });\n\n  it('should support curl', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n\n    await request(server)\n      .get('/urllib?method=curl')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should support json', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'get', {\n      data: { method: 'get' },\n    });\n    app.mockHttpclient(url, 'post', {\n      data: { method: 'post' },\n    });\n\n    await request(server)\n      .get('/urllib?dataType=json')\n      .expect({\n        get: { method: 'get' },\n        post: { method: 'post' },\n      })\n      .expect(200);\n  });\n\n  it('should support text', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n\n    await request(server)\n      .get('/urllib?dataType=text')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should exits req headers', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url test',\n    });\n    await request(server)\n      .get('/mock_urllib')\n      .expect({})\n      .expect(200);\n  });\n\n  it('should mock url path support RegExp', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(/\\/mock_url$/, {\n      data: Buffer.from('mock response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock response',\n        post: 'mock response',\n      })\n      .expect(200);\n  });\n\n  it('should mock full url support RegExp', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(/http:\\/\\/127\\.0\\.0\\.1:\\d+\\/mock_url$/, [ 'get', 'post' ], {\n      data: Buffer.from('mock full 127 url response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock full 127 url response',\n        post: 'mock full 127 url response',\n      })\n      .expect(200);\n  });\n\n  it('should use copy of mock data', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(/\\/mock_url$/, {\n      data: { a: 1 },\n    });\n\n    await request(server)\n      .get('/data_type')\n      .expect({\n        a: 1,\n      })\n      .expect(200);\n\n    await request(server)\n      .get('/data_type')\n      .expect({\n        a: 1,\n      })\n      .expect(200);\n  });\n\n  it('should support fn', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'get', (url, opt) => {\n      return `mock ${url} with ${opt.path}`;\n    });\n    app.mockHttpclient(url, 'post', 'mock url post');\n\n    await request(server)\n      .get('/urllib')\n      .query({ data: JSON.stringify({ a: 'b' }) })\n      .expect({\n        get: `mock ${url}?a=b with /mock_url?a=b`,\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  // not support in urllib3\n  it.skip('should support async function', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'get', async (url, opt) => {\n      await sleep(100);\n      return `mock ${url} with ${opt.data.a}`;\n    });\n    app.mockHttpclient(url, 'post', 'mock url post');\n\n    await request(server)\n      .get('/urllib')\n      .query({ data: JSON.stringify({ a: 'b' }) })\n      .expect({\n        get: `mock ${url} with b`,\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should mock fn with multi-request without error', async () => {\n    app.mockCsrf();\n    let i = 0;\n    app.mockHttpclient(url, 'post', () => {\n      i++;\n      return {};\n    });\n\n    await request(server).get('/urllib').expect(200);\n    await request(server).get('/urllib').expect(200);\n    await request(server).get('/urllib').expect(200);\n    assert(i === 3);\n  });\n});\n"
  },
  {
    "path": "test/mock_httpclient_next_h2.test.js",
    "content": "const pedding = require('pedding');\nconst path = require('path');\nconst fs = require('fs');\nconst request = require('supertest');\nconst assert = require('assert');\nconst mm = require('..');\n\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_httpclient_next_h2.test.js', () => {\n  let app;\n  let server;\n  let url;\n  let url2;\n  before(() => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo_next_h2'),\n    });\n    return app.ready();\n  });\n  before(() => {\n    server = app.listen();\n    url = `http://127.0.0.1:${server.address().port}/mock_url`;\n    url2 = `http://127.0.0.1:${server.address().port}/mock_url2`;\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should mock url and get response event on urllib', done => {\n    done = pedding(2, done);\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: Buffer.from('mock all response'),\n    });\n\n    request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock all response',\n        post: 'mock all response',\n      })\n      .expect(200, done);\n\n    app.httpclient.once('response', result => {\n      assert('url' in result.req);\n      // assert('size' in result.req);\n      assert('options' in result.req);\n\n      assert(result.res.status === 200);\n      assert(result.res.statusCode === 200);\n      assert.deepEqual(result.res.headers, {});\n      assert(result.res.rt);\n      done();\n    });\n\n    let count = 0;\n    app.httpclient.on('response', result => {\n      if (count === 0) {\n        const options = result.req.options;\n        assert(options.method === 'GET');\n      } else if (count === 1) {\n        const options = result.req.options;\n        assert(options.method === 'POST');\n        assert(options.headers['x-custom'] === 'custom');\n      }\n      count++;\n    });\n  });\n\n  it('should mock url using app.mockAgent().intercept()', async () => {\n    app.mockCsrf();\n    app.mockAgent()\n      .get(new URL(url).origin)\n      .intercept({\n        path: '/mock_url',\n        method: 'GET',\n      })\n      .reply(200, 'mock GET response');\n    app.mockAgent()\n      .get(new URL(url).origin)\n      .intercept({\n        path: '/mock_url',\n        method: 'POST',\n      })\n      .reply(200, 'mock POST response');\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock GET response',\n        post: 'mock POST response',\n      })\n      .expect(200);\n  });\n\n  it('should support on streaming', async () => {\n    app.mockHttpclient(url, 'get', {\n      data: fs.readFileSync(__filename),\n    });\n\n    const res = await request(server)\n      .get('/streaming')\n      .expect(200);\n    assert.match(res.body.toString(), /should support on streaming/);\n    assert.equal(res.body.toString(), fs.readFileSync(__filename, 'utf8'));\n  });\n\n  it('should mock url support multi method', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, [ 'get', 'post' ], {\n      data: Buffer.from('mock response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock response',\n        post: 'mock response',\n      })\n      .expect(200);\n  });\n\n  it('should mockHttpclient call multi times work with Regex', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(/\\/not\\/match\\//, {\n      data: Buffer.from('mock not match response'),\n    });\n    app.mockHttpclient(/\\/mock_url/, {\n      data: Buffer.from('mock 1 match response'),\n    });\n    app.mockHttpclient(/\\/mock_url/, {\n      data: Buffer.from('mock 2 match response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock 1 match response',\n        post: 'mock 1 match response',\n      })\n      .expect(200);\n  });\n\n  it('should mockHttpclient call multi times work with url string', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(`${url}-not-match`, {\n      data: Buffer.from('mock not match response'),\n    });\n    app.mockHttpclient(url, {\n      data: Buffer.from('mock 1 match response'),\n    });\n    app.mockHttpclient(url, {\n      data: Buffer.from('mock 2 match response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock 1 match response',\n        post: 'mock 1 match response',\n      })\n      .expect(200);\n  });\n\n  it('should mock url method support *', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, '*', {\n      data: Buffer.from('mock * response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock * response',\n        post: 'mock * response',\n      })\n      .expect(200);\n  });\n\n  it('should mock url post', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: Buffer.from('mock url post'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should auto restore after each case', async () => {\n    app.mockCsrf();\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'url get',\n        post: 'url post',\n      })\n      .expect(200);\n  });\n\n  it('should use first mock data on duplicate url mock', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: Buffer.from('mock url1 first post'),\n    });\n    // should ignore this same url mock data, use the first mock data\n    app.mockHttpclient(url, 'post', {\n      data: Buffer.from('mock url1 second post'),\n    });\n    app.mockHttpclient(url2, 'post', {\n      data: Buffer.from('mock url2 post'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'url get',\n        post: 'mock url1 first post',\n      })\n      .expect(200);\n    await request(server)\n      .get('/urllib')\n      .query({\n        mock_url: '/mock_url2',\n      })\n      .expect({\n        get: 'url get',\n        post: 'mock url2 post',\n      })\n      .expect(200);\n  });\n\n  it('should mock work on query', async () => {\n    app.mockCsrf();\n    // mockHttpclient not support query, should use mockAgent instead\n    app.mockHttpclient(`${url}?foo=foo1`, 'get', {\n      data: Buffer.from('mock foo1'),\n    });\n    app.mockHttpclient(`${url}?foo=foo2`, 'get', {\n      data: Buffer.from('mock foo1'),\n    });\n    await request(server)\n      .get('/urllib')\n      .query({ foo: 'foo1' })\n      .expect({\n        get: 'mock foo1',\n        post: 'url post',\n      })\n      .expect(200);\n    await request(server)\n      .get('/urllib')\n      .query({ foo: 'foo2' })\n      .expect({\n        get: 'mock foo1',\n        post: 'url post',\n      })\n      .expect(200);\n    await app.mockAgentRestore();\n\n    app.mockAgent().get(new URL(url).origin)\n      .intercept({\n        path: '/mock_url?foo=foo1',\n        method: 'GET',\n      })\n      .reply(200, 'mock new foo1');\n    app.mockAgent().get(new URL(url).origin)\n      .intercept({\n        path: '/mock_url?foo=foo2',\n        method: 'GET',\n      })\n      .reply(200, 'mock new foo2');\n    await request(server)\n      .get('/urllib')\n      .query({ foo: 'foo1' })\n      .expect({\n        get: 'mock new foo1',\n        post: 'url post',\n      })\n      .expect(200);\n    await request(server)\n      .get('/urllib')\n      .query({ foo: 'foo2' })\n      .expect({\n        get: 'mock new foo2',\n        post: 'url post',\n      })\n      .expect(200);\n  });\n\n  it('should mock url get and post', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should support request', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should support persist = false', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url',\n      persist: false,\n    });\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'mock url',\n        post: 'url post',\n      })\n      .expect(200);\n  });\n\n  it('should support persist = true and ignore repeats = 1', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url',\n      persist: true,\n      repeats: 1,\n    });\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'mock url',\n        post: 'mock url',\n      })\n      .expect(200);\n  });\n\n  it('should support persist = false and repeats = 2', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url',\n      delay: 100,\n      persist: false,\n      repeats: 2,\n    });\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'mock url',\n        post: 'mock url',\n      })\n      .expect(200);\n\n    await request(server)\n      .get('/urllib?method=request')\n      .expect({\n        get: 'url get',\n        post: 'url post',\n      })\n      .expect(200);\n  });\n\n  it('should support curl', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n\n    await request(server)\n      .get('/urllib?method=curl')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should support json', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'get', {\n      data: { method: 'get' },\n    });\n    app.mockHttpclient(url, 'post', {\n      data: { method: 'post' },\n    });\n\n    await request(server)\n      .get('/urllib?dataType=json')\n      .expect({\n        get: { method: 'get' },\n        post: { method: 'post' },\n      })\n      .expect(200);\n  });\n\n  it('should support text', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'post', {\n      data: 'mock url post',\n    });\n    app.mockHttpclient(url, {\n      data: 'mock url get',\n    });\n\n    await request(server)\n      .get('/urllib?dataType=text')\n      .expect({\n        get: 'mock url get',\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should exits req headers', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, {\n      data: 'mock url test',\n    });\n    await request(server)\n      .get('/mock_urllib')\n      .expect({})\n      .expect(200);\n  });\n\n  it('should mock url path support RegExp', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(/\\/mock_url$/, {\n      data: Buffer.from('mock response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock response',\n        post: 'mock response',\n      })\n      .expect(200);\n  });\n\n  it('should mock full url support RegExp', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(/http:\\/\\/127\\.0\\.0\\.1:\\d+\\/mock_url$/, [ 'get', 'post' ], {\n      data: Buffer.from('mock full 127 url response'),\n    });\n\n    await request(server)\n      .get('/urllib')\n      .expect({\n        get: 'mock full 127 url response',\n        post: 'mock full 127 url response',\n      })\n      .expect(200);\n  });\n\n  it('should use copy of mock data', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(/\\/mock_url$/, {\n      data: { a: 1 },\n    });\n\n    await request(server)\n      .get('/data_type')\n      .expect({\n        a: 1,\n      })\n      .expect(200);\n\n    await request(server)\n      .get('/data_type')\n      .expect({\n        a: 1,\n      })\n      .expect(200);\n  });\n\n  it('should support fn', async () => {\n    app.mockCsrf();\n    app.mockHttpclient(url, 'get', (url, opt) => {\n      return `mock ${url} with ${opt.path}`;\n    });\n    app.mockHttpclient(url, 'post', 'mock url post');\n\n    await request(server)\n      .get('/urllib')\n      .query({ data: JSON.stringify({ a: 'b' }) })\n      .expect({\n        get: `mock ${url}?a=b with /mock_url?a=b`,\n        post: 'mock url post',\n      })\n      .expect(200);\n  });\n\n  it('should mock fn with multi-request without error', async () => {\n    app.mockCsrf();\n    let i = 0;\n    app.mockHttpclient(url, 'post', () => {\n      i++;\n      return {};\n    });\n\n    await request(server).get('/urllib').expect(200);\n    await request(server).get('/urllib').expect(200);\n    await request(server).get('/urllib').expect(200);\n    assert(i === 3);\n  });\n});\n"
  },
  {
    "path": "test/mock_request.test.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst mm = require('..');\n\ndescribe('test/mock_httpclient.test.js', () => {\n  describe('app mode', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir: 'request',\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n    afterEach(mm.restore);\n\n    it('should test app with request', () => {\n      return app.httpRequest()\n        .get('/')\n        .expect(200)\n        .expect('hello world');\n    });\n\n    it('should test app with request on pathFor', () => {\n      return app.httpRequest()\n        .get('home')\n        .expect(200)\n        .expect('hello world');\n    });\n\n    it('should GET session path work', () => {\n      return app.httpRequest()\n        .get('session')\n        .expect(200)\n        .expect('hello session');\n    });\n\n    it('should GET wrong pathFor name throw error', () => {\n      try {\n        app.httpRequest()\n          .get('session-404')\n          .expect(200)\n          .expect('hello world');\n        throw new Error('should not run this');\n      } catch (err) {\n        assert(err);\n        assert(err.message === 'Can\\'t find router:session-404, please check your \\'app/router.js\\'');\n      }\n    });\n\n    it('should test with expectHeader(header) and unexpectHeader(header)', () => {\n      return app.httpRequest()\n        .get('/')\n        .expect(200)\n        .expect('hello world')\n        .expectHeader('set-cookie')\n        .unexpectHeader('cache-control');\n    });\n\n    it('should test with expectHeader(header) and unexpectHeader(header) throw error', function* () {\n      try {\n        yield app.httpRequest()\n          .get('/')\n          .expect(200)\n          .expect('hello world')\n          .expectHeader('set-cookie1');\n      } catch (err) {\n        assert(err.message === 'expected \"set-cookie1\" header field');\n      }\n\n      try {\n        yield app.httpRequest()\n          .get('/')\n          .expect(200)\n          .expect('hello world')\n          .unexpectHeader('set-cookie');\n      } catch (err) {\n        assert(err.message.startsWith('unexpected \"set-cookie\" header field, got \\\"'));\n      }\n    });\n\n    it('should test with expectHeader(header, done)', done => {\n      app.httpRequest()\n        .get('/')\n        .expectHeader('set-cookie', done);\n    });\n\n    it('should test with unexpectHeader(header, done)', done => {\n      app.httpRequest()\n        .get('/')\n        .unexpectHeader('cache-control', done);\n    });\n  });\n\n  describe('cluster mode', () => {\n    let app;\n    before(() => {\n      app = mm.cluster({\n        baseDir: 'request',\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n    afterEach(mm.restore);\n\n    it('should test app with request', () => {\n      return app.httpRequest()\n        .get('/')\n        .expect(200)\n        .expect('hello world');\n    });\n\n    it('should test app with request on pathFor', () => {\n      return app.httpRequest()\n        .get('home')\n        .expect(200)\n        .expect('hello world');\n    });\n\n    it('should GET session path work', () => {\n      return app.httpRequest()\n        .get('session')\n        .expect(200)\n        .expect('hello session');\n    });\n\n    it('should GET wrong pathFor name throw error', () => {\n      try {\n        app.httpRequest()\n          .get('session-404')\n          .expect(200)\n          .expect('hello world');\n        throw new Error('should not run this');\n      } catch (err) {\n        assert(err);\n        assert(err.message === 'Can\\'t find router:session-404, please check your \\'app/router.js\\'');\n      }\n    });\n\n    it('should test with expectHeader(header) and unexpectHeader(header)', () => {\n      return app.httpRequest()\n        .get('/')\n        .expect(200)\n        .expect('hello world')\n        .expectHeader('set-cookie')\n        .unexpectHeader('cache-control');\n    });\n\n    it('should test with expectHeader(header) and unexpectHeader(header) throw error', function* () {\n      try {\n        yield app.httpRequest()\n          .get('/')\n          .expect(200)\n          .expect('hello world')\n          .expectHeader('set-cookie1');\n      } catch (err) {\n        assert(err.message === 'expected \"set-cookie1\" header field');\n      }\n\n      try {\n        yield app.httpRequest()\n          .get('/')\n          .expect(200)\n          .expect('hello world')\n          .unexpectHeader('set-cookie');\n      } catch (err) {\n        assert(err.message.startsWith('unexpected \"set-cookie\" header field, got \\\"'));\n      }\n    });\n\n    it('should test with expectHeader(header, done)', done => {\n      app.httpRequest()\n        .get('/')\n        .expectHeader('set-cookie', done);\n    });\n\n    it('should test with unexpectHeader(header, done)', done => {\n      app.httpRequest()\n        .get('/')\n        .unexpectHeader('cache-control', done);\n    });\n  });\n});\n"
  },
  {
    "path": "test/mock_service.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_service.test.js', () => {\n  let app;\n  before(async () => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo'),\n    });\n    await app.ready();\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should return from service', () => {\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: 'bar',\n        foo2: 'bar',\n        foo3: 'bar',\n        thirdService: 'third',\n      });\n  });\n\n  it('should return from service when mock with data', () => {\n    app.mockService('foo', 'get', 'foo');\n    app.mockService('foo', 'getSync', 'foo');\n    app.mockService('bar.foo', 'get', 'foo');\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: 'foo',\n        foo2: 'foo',\n        foo3: 'foo',\n        thirdService: 'third',\n      });\n  });\n\n  it('mock repeat succeess', () => {\n    app.mockService('foo', 'get', 'foo');\n    app.mockService('foo', 'get', 'foo');\n    app.mockService('foo', 'getSync', 'foo');\n    app.mockService('foo', 'getSync', 'foo');\n    app.mockService('bar.foo', 'get', 'foo');\n    app.mockService('bar.foo', 'get', 'foo');\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: 'foo',\n        foo2: 'foo',\n        foo3: 'foo',\n        thirdService: 'third',\n      });\n  });\n\n  it.skip('mock error succeess', async () => {\n    app.mockService('foo', 'get', new Error('async error'));\n    try {\n      const ctx = app.mockContext();\n      await ctx.service.foo.get();\n      throw new Error('should not execute');\n    } catch (err) {\n      assert(err.message === 'async error');\n    }\n  });\n\n  it.skip('mock sync error succeess', async () => {\n    app.mockService('foo', 'getSync', new Error('sync error'));\n    try {\n      const ctx = app.mockContext();\n      await ctx.service.foo.getSync();\n      throw new Error('should not execute');\n    } catch (err) {\n      assert(err.message === 'sync error');\n    }\n  });\n\n  it('should return from service when mock with normal function', () => {\n    app.mockService('foo', 'get', () => 'foo');\n    app.mockService('foo', 'getSync', () => 'foo');\n    app.mockService('bar.foo', 'get', () => 'foo');\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: 'foo',\n        foo2: 'foo',\n        foo3: 'foo',\n        thirdService: 'third',\n      });\n  });\n\n  it('should support old service format', () => {\n    app.mockService('old', 'test', 'test');\n    return app.httpRequest()\n      .get('/service/old')\n      .expect('test');\n  });\n\n  it('should throw', () => {\n    assert.throws(() => {\n      app.mockService('foo', 'not_exist', 'foo');\n    }, /property not_exist in original object must be function/);\n  });\n\n  it('should return from service when mock with generator', () => {\n    app.mockService('foo', 'get', async () => {\n      return 'foo';\n    });\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: 'foo',\n        foo2: 'bar',\n        foo3: 'bar',\n        thirdService: 'third',\n      });\n  });\n\n  it('should return from service when mock with 3 level', () => {\n    app.mockService('foo', 'get', '1 level service');\n    app.mockService('bar.foo', 'get', '2 level service');\n    app.mockService('third.bar.foo', 'get', '3 level service');\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: '1 level service',\n        foo2: '2 level service',\n        foo3: 'bar',\n        thirdService: '3 level service',\n      });\n  });\n\n  it('should return from service when mock with error', () => {\n    app.mockService('foo', 'get', async () => {\n      throw new Error('mock service foo.get error');\n    });\n    return app.httpRequest()\n      .get('/service')\n      .expect(/mock service foo\\.get error/)\n      .expect(500);\n  });\n\n  describe('app.mockServiceError()', () => {\n    it('should default mock error', () => {\n      app.mockServiceError('foo', 'get');\n      return app.httpRequest()\n        .get('/service')\n        .expect(/mock get error/)\n        .expect(500);\n    });\n\n    it('should create custom mock error with string', () => {\n      app.mockServiceError('foo', 'get', 'mock service foo.get error1');\n      return app.httpRequest()\n        .get('/service')\n        .expect(/mock service foo\\.get error1/)\n        .expect(500);\n    });\n\n    it('should return custom mock error', () => {\n      app.mockServiceError('foo', 'get', new Error('mock service foo.get error2'));\n      return app.httpRequest()\n        .get('/service')\n        .expect(/mock service foo\\.get error2/)\n        .expect(500);\n    });\n  });\n});\n"
  },
  {
    "path": "test/mock_service_async.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst request = require('supertest');\nconst assert = require('assert');\nconst mm = require('..');\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_service_async.test.js', () => {\n  let app;\n  before(async () => {\n    app = mm.app({\n      baseDir: path.join(fixtures, 'demo-async'),\n    });\n    await app.ready();\n  });\n  after(() => app.close());\n  afterEach(mm.restore);\n\n  it('should return from service', done => {\n    request(app.callback())\n      .get('/service')\n      .expect({\n        foo1: 'bar',\n        foo2: 'bar',\n        foo3: 'bar',\n        thirdService: 'third',\n      }, done);\n  });\n\n  it('should return from service when mock with data', done => {\n    app.mockService('foo', 'get', 'foo');\n    app.mockService('foo', 'getSync', 'foo');\n    app.mockService('bar.foo', 'get', 'foo');\n    request(app.callback())\n      .get('/service')\n      .expect({\n        foo1: 'foo',\n        foo2: 'foo',\n        foo3: 'foo',\n        thirdService: 'third',\n      }, done);\n  });\n\n  it('should return from service when mock with normal function', done => {\n    app.mockService('foo', 'get', () => 'foo');\n    app.mockService('foo', 'getSync', () => 'foo');\n    app.mockService('bar.foo', 'get', () => 'foo');\n    request(app.callback())\n      .get('/service')\n      .expect({\n        foo1: 'foo',\n        foo2: 'foo',\n        foo3: 'foo',\n        thirdService: 'third',\n      }, done);\n  });\n\n  it('should throw', () => {\n    assert.throws(() => {\n      app.mockService('foo', 'not_exist', 'foo');\n    }, /property not_exist in original object must be function/);\n  });\n\n  it('should return from service when mock with generator', done => {\n    app.mockService('foo', 'get', async () => {\n      return 'foo';\n    });\n    request(app.callback())\n      .get('/service')\n      .expect({\n        foo1: 'foo',\n        foo2: 'bar',\n        foo3: 'bar',\n        thirdService: 'third',\n      }, done);\n  });\n\n  it('should return from service when mock with 3 level', done => {\n    app.mockService('foo', 'get', '1 level service');\n    app.mockService('bar.foo', 'get', '2 level service');\n    app.mockService('third.bar.foo', 'get', '3 level service');\n    request(app.callback())\n      .get('/service')\n      .expect({\n        foo1: '1 level service',\n        foo2: '2 level service',\n        foo3: 'bar',\n        thirdService: '3 level service',\n      }, done);\n  });\n\n  it('should return from service when mock with error', done => {\n    app.mockService('foo', 'get', async () => {\n      throw new Error('mock service foo.get error');\n    });\n    request(app.callback())\n      .get('/service')\n      .expect(/mock service foo\\.get error/)\n      .expect(500, done);\n  });\n\n  describe('app.mockServiceError()', () => {\n    it('should default mock error', done => {\n      app.mockServiceError('foo', 'get');\n      request(app.callback())\n        .get('/service')\n        .expect(/mock get error/)\n        .expect(500, done);\n    });\n\n    it('should create custom mock error with string', done => {\n      app.mockServiceError('foo', 'get', 'mock service foo.get error1');\n      request(app.callback())\n        .get('/service')\n        .expect(/mock service foo\\.get error1/)\n        .expect(500, done);\n    });\n\n    it('should return custom mock error', done => {\n      app.mockServiceError('foo', 'get', new Error('mock service foo.get error2'));\n      request(app.callback())\n        .get('/service')\n        .expect(/mock service foo\\.get error2/)\n        .expect(500, done);\n    });\n  });\n\n});\n"
  },
  {
    "path": "test/mock_service_cluster.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst assert = require('assert');\nconst mm = require('..');\n\nconst fixtures = path.join(__dirname, 'fixtures');\n\ndescribe('test/mock_service_cluster.test.js', () => {\n  let app;\n  before(() => {\n    app = mm.cluster({\n      baseDir: path.join(fixtures, 'demo'),\n    });\n    return app.ready();\n  });\n  after(() => app.close());\n\n  afterEach(mm.restore);\n\n  it('should return from service', () => {\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: 'bar',\n        foo2: 'bar',\n        foo3: 'bar',\n        thirdService: 'third',\n      });\n  });\n\n  it('should return from service when mock with data', () => {\n    app.mockService('foo', 'get', 'foo');\n    app.mockService('foo', 'getSync', 'foo');\n    app.mockService('bar.foo', 'get', 'foo');\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: 'foo',\n        foo2: 'foo',\n        foo3: 'foo',\n        thirdService: 'third',\n      });\n  });\n\n  it('should support old service format', () => {\n    app.mockService('old', 'test', 'test');\n    return app.httpRequest()\n      .get('/service/old')\n      .expect('test');\n  });\n\n  it('should throw not exists service error', () => {\n    assert.throws(() => {\n      app.mockService('foo', 'not_exist', 'foo');\n    }, /property not_exist in original object must be function/);\n  });\n\n  it('should return from service when mock with generator', () => {\n    app.mockService('foo', 'get', function* () {\n      return 'foo';\n    });\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: 'foo',\n        foo2: 'bar',\n        foo3: 'bar',\n        thirdService: 'third',\n      });\n  });\n\n  it('should return from service when mock with 3 level', () => {\n    app.mockService('foo', 'get', '1 level service');\n    app.mockService('bar.foo', 'get', '2 level service');\n    app.mockService('third.bar.foo', 'get', '3 level service');\n    return app.httpRequest()\n      .get('/service')\n      .expect({\n        foo1: '1 level service',\n        foo2: '2 level service',\n        foo3: 'bar',\n        thirdService: '3 level service',\n      });\n  });\n\n  it('should return from service when mock with error', () => {\n    app.mockService('foo', 'get', function* () {\n      throw new Error('mock service foo.get error');\n    });\n    return app.httpRequest()\n      .get('/service')\n      .expect(/mock service foo\\.get error/)\n      .expect(500);\n  });\n\n  describe('app.mockServiceError()', () => {\n    it('should default mock error', () => {\n      app.mockServiceError('foo', 'get');\n      return app.httpRequest()\n        .get('/service')\n        .expect(/mock get error/)\n        .expect(500);\n    });\n\n    it('should create custom mock error with string', () => {\n      app.mockServiceError('foo', 'get', 'mock service foo.get error1');\n      return app.httpRequest()\n        .get('/service')\n        .expect(/mock service foo\\.get error1/)\n        .expect(500);\n    });\n\n    it('should return custom mock error', () => {\n      const err = new Error('mock service foo.get error2');\n      err.foo = 'bar';\n      app.mockServiceError('foo', 'get', err);\n      return app.httpRequest()\n        .get('/service')\n        .expect(/mock service foo\\.get error2/)\n        .expect(500);\n    });\n  });\n});\n"
  },
  {
    "path": "test/mock_session.test.js",
    "content": "'use strict';\n\nconst mm = require('..');\nconst assert = require('assert');\n\ndescribe('test/mock_session.test.js', () => {\n  afterEach(mm.restore);\n\n  describe('single process mode', () => {\n    let app;\n    before(() => {\n      app = mm.app({\n        baseDir: 'demo',\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should mock session', () => {\n      const obj = {\n        user: {\n          foo: 'bar',\n        },\n        hello: 'egg mock session data',\n      };\n\n      // const ctx = app.mockContext();\n      app.mockSession(obj);\n      // assert.deepEqual(ctx.session, obj);\n\n      return app.httpRequest()\n        .get('/session')\n        .expect({\n          user: {\n            foo: 'bar',\n          },\n          hello: 'egg mock session data',\n        });\n    });\n\n    it.skip('should support mock session with plain type', () => {\n      const ctx = app.mockContext();\n      app.mockSession();\n      app.mockSession('123');\n      assert(ctx.session === '123');\n      assert(!ctx.session.save);\n    });\n\n    it('should mock restore', () => {\n      return app.httpRequest()\n        .get('/session')\n        .expect({});\n    });\n  });\n\n  describe('cluster process mode', () => {\n    let app;\n    before(() => {\n      app = mm.cluster({\n        baseDir: 'demo',\n      });\n      return app.ready();\n    });\n    after(() => app.close());\n\n    it('should mock session', () => {\n      app.mockSession({\n        user: {\n          foo: 'bar',\n        },\n        hello: 'egg mock session data',\n      });\n      return app.httpRequest()\n        .get('/session')\n        .expect({\n          user: {\n            foo: 'bar',\n          },\n          hello: 'egg mock session data',\n        });\n    });\n\n    it('should mock restore', () => {\n      return app.httpRequest()\n        .get('/session')\n        .expect({});\n    });\n  });\n});\n"
  },
  {
    "path": "test/parallel.test.js",
    "content": "const path = require('path');\nconst agentRegister = require('../register');\n\ndescribe('test/parallel.test.js', () => {\n  before(async () => {\n    await agentRegister.mochaGlobalSetup();\n    process.env.ENABLE_MOCHA_PARAELLEL = 'true';\n    process.env.AUTO_AGENT = 'true';\n    process.env.EGG_BASE_DIR = path.join(__dirname, './fixtures/apps/foo');\n  });\n\n  after(async () => {\n    await agentRegister.mochaGlobalTeardown();\n    delete process.env.ENABLE_MOCHA_PARAELLEL;\n    delete process.env.AUTO_AGENT;\n    delete process.env.EGG_BASE_DIR;\n  });\n\n  it('should work', async () => {\n    const { app } = require('../bootstrap');\n    await app.ready();\n    await app.httpRequest()\n      .get('/')\n      .expect(200)\n      .expect('foo');\n    await app.close();\n  });\n});\n"
  },
  {
    "path": "test/parallel_hook.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst coffee = require('coffee');\nconst mock = require('mm');\n\ndescribe('test/bootstrap-plugin.test.js', () => {\n\n  after(() => mock.restore());\n\n  it('should throw', async () => {\n    return coffee.fork(require.resolve('mocha/bin/mocha'), [\n      '-r', path.join(__dirname, '../lib/parallel/agent_register'),\n      '--parallel', '--jobs', '2', '--exit',\n    ], {\n      cwd: path.join(__dirname, './fixtures/apps/parallel-test'),\n    })\n      // .debug()\n      .expect('code', 0)\n      .expect('stdout', /3 passing/)\n      .end();\n  });\n});\n"
  },
  {
    "path": "test/tsd.test.js",
    "content": "'use strict';\n\nconst path = require('path');\nconst { execSync } = require('child_process');\n\ndescribe('test/tsd.test.js', () => {\n  it('should tsd run success', () => {\n    execSync('tsd', {\n      cwd: path.dirname(__dirname),\n    });\n  });\n});\n"
  }
]