diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs-5.x.yml
similarity index 74%
rename from .github/workflows/nodejs.yml
rename to .github/workflows/nodejs-5.x.yml
index b0f6bd0f..8f275748 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs-5.x.yml
@@ -1,4 +1,4 @@
-name: CI
+name: CI for 5.x
on:
push:
@@ -13,3 +13,5 @@ jobs:
uses: node-modules/github-actions/.github/workflows/node-test.yml@master
with:
version: '14.19.0, 14, 16, 18, 20'
+ secrets:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/release-5.x.yml b/.github/workflows/release-5.x.yml
new file mode 100644
index 00000000..79331a82
--- /dev/null
+++ b/.github/workflows/release-5.x.yml
@@ -0,0 +1,12 @@
+name: Release for 5.x
+on:
+ push:
+ branches: [ 5.x ]
+
+jobs:
+ release:
+ name: Node.js
+ uses: eggjs/github-actions/.github/workflows/node-release.yml@master
+ secrets:
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+ GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 537c68f9..7c7b3882 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,5 @@ test/fixtures/egg/node_modules/egg-core
package-lock.json
run
test/fixtures/*/timing.json
+.tshy*
+.package-lock.json
diff --git a/README.md b/README.md
index 6301c108..d1874c1d 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# egg-core
[![NPM version][npm-image]][npm-url]
-[![Node.js CI](https://github.com/eggjs/egg-core/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eggjs/egg-core/actions/workflows/nodejs.yml)
+[![Node.js CI](https://github.com/eggjs/egg-core/actions/workflows/nodejs-5.x.yml/badge.svg)](https://github.com/eggjs/egg-core/actions/workflows/nodejs-5.x.yml)
[![Test coverage][codecov-image]][codecov-url]
[![Known Vulnerabilities][snyk-image]][snyk-url]
[![npm download][download-image]][download-url]
@@ -17,7 +17,7 @@
A core Pluggable framework based on [koa](https://github.com/koajs/koa).
-**Don't use it directly, see [egg].**
+**Don't use it directly, see [egg](https://github.com/eggjs/egg).**
## Usage
@@ -236,6 +236,7 @@ filter | `Function` | a function that filter the exports which can b
## Timing
EggCore record boot progress with `Timing`, include:
+
- Process start time
- Script start time(node don't implement an interface like `process.uptime` to record the script start running time, framework can implement a prestart file used with node `--require` options to set `process.scriptTime`)
- Application start time
@@ -274,18 +275,8 @@ Please open an issue [here](https://github.com/eggjs/egg/issues).
[MIT](LICENSE)
-[egg]: https://github.com/eggjs/egg
-
-
## Contributors
-|[![](https://avatars.githubusercontent.com/u/360661?v=4)
popomore](https://github.com/popomore)
|[![](https://avatars.githubusercontent.com/u/985607?v=4)
dead-horse](https://github.com/dead-horse)
|[![](https://avatars.githubusercontent.com/u/156269?v=4)
fengmk2](https://github.com/fengmk2)
|[![](https://avatars.githubusercontent.com/u/227713?v=4)
atian25](https://github.com/atian25)
|[![](https://avatars.githubusercontent.com/u/5856440?v=4)
whxaxes](https://github.com/whxaxes)
|[![](https://avatars.githubusercontent.com/u/1207064?v=4)
gxcsoccer](https://github.com/gxcsoccer)
|
-| :---: | :---: | :---: | :---: | :---: | :---: |
-|[![](https://avatars.githubusercontent.com/u/6897780?v=4)
killagu](https://github.com/killagu)
|[![](https://avatars.githubusercontent.com/u/2170848?v=4)
iyuq](https://github.com/iyuq)
|[![](https://avatars.githubusercontent.com/u/5243774?v=4)
ngot](https://github.com/ngot)
|[![](https://avatars.githubusercontent.com/u/17722900?v=4)
initial-wu](https://github.com/initial-wu)
|[![](https://avatars.githubusercontent.com/u/1763067?v=4)
waitingsong](https://github.com/waitingsong)
|[![](https://avatars.githubusercontent.com/u/7315743?v=4)
AnzerWall](https://github.com/AnzerWall)
|
-|[![](https://avatars.githubusercontent.com/u/174904?v=4)
army8735](https://github.com/army8735)
|[![](https://avatars.githubusercontent.com/u/5938871?v=4)
njugray](https://github.com/njugray)
|[![](https://avatars.githubusercontent.com/u/327019?v=4)
JacksonTian](https://github.com/JacksonTian)
|[![](https://avatars.githubusercontent.com/u/16460813?v=4)
JimmyDaddy](https://github.com/JimmyDaddy)
|[![](https://avatars.githubusercontent.com/u/2842176?v=4)
XadillaX](https://github.com/XadillaX)
|[![](https://avatars.githubusercontent.com/u/6913898?v=4)
monkindey](https://github.com/monkindey)
|
-|[![](https://avatars.githubusercontent.com/u/1148428?v=4)
mattma](https://github.com/mattma)
|[![](https://avatars.githubusercontent.com/u/456108?v=4)
shaoshuai0102](https://github.com/shaoshuai0102)
|[![](https://avatars.githubusercontent.com/u/7530656?v=4)
zhang740](https://github.com/zhang740)
|[![](https://avatars.githubusercontent.com/u/457552?v=4)
dsonet](https://github.com/dsonet)
|[![](https://avatars.githubusercontent.com/u/3995814?v=4)
chenbin92](https://github.com/chenbin92)
|[![](https://avatars.githubusercontent.com/u/19908330?v=4)
hyj1991](https://github.com/hyj1991)
|
-[![](https://avatars.githubusercontent.com/u/8816730?v=4)
maxming2333](https://github.com/maxming2333)
|[![](https://avatars.githubusercontent.com/u/26317926?v=4)
supperchong](https://github.com/supperchong)
|[![](https://avatars.githubusercontent.com/u/18463189?v=4)
ZhangDianPeng](https://github.com/ZhangDianPeng)
|[![](https://avatars.githubusercontent.com/u/15242708?v=4)
mosaic101](https://github.com/mosaic101)
-
-This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Wed Nov 24 2021 22:24:39 GMT+0800`.
+[![Contributors](https://contrib.rocks/image?repo=eggjs/core)](https://github.com/eggjs/core/graphs/contributors)
-
+Made with [contributors-img](https://contrib.rocks).
diff --git a/lib/egg.js b/lib/egg.js
index 9db5022d..d0f5b52c 100644
--- a/lib/egg.js
+++ b/lib/egg.js
@@ -25,11 +25,23 @@ class EggCore extends KoaApplication {
* @param {String} [options.baseDir=process.cwd()] - the directory of application
* @param {String} [options.type=application|agent] - whether it's running in app worker or agent worker
* @param {Object} [options.plugins] - custom plugins
+ * @param {Object | String} [options.pathToRegexpModule] - custom `path-to-regexp` module, default is `path-to-regexp@1`
* @since 1.0.0
*/
constructor(options = {}) {
options.baseDir = options.baseDir || process.cwd();
options.type = options.type || 'application';
+ if (typeof options.pathToRegexpModule === 'string') {
+ /**
+ * Usage:
+ * ```js
+ * const app = new Application({
+ * pathToRegexpModule: '/path/to/path-to-regexp-v8',
+ * });
+ * ```
+ */
+ options.pathToRegexpModule = require(options.pathToRegexpModule);
+ }
assert(typeof options.baseDir === 'string', 'options.baseDir required, and must be a string');
assert(fs.existsSync(options.baseDir), `Directory ${options.baseDir} not exists`);
@@ -301,7 +313,10 @@ class EggCore extends KoaApplication {
if (this[ROUTER]) {
return this[ROUTER];
}
- const router = this[ROUTER] = new Router({ sensitive: true }, this);
+ const router = this[ROUTER] = new Router({
+ sensitive: true,
+ pathToRegexpModule: this.options.pathToRegexpModule,
+ }, this);
// register router middleware
this.beforeStart(() => {
this.use(router.middleware());
diff --git a/lib/loader/mixin/middleware.js b/lib/loader/mixin/middleware.js
index 361aeae5..247b39fc 100644
--- a/lib/loader/mixin/middleware.js
+++ b/lib/loader/mixin/middleware.js
@@ -76,7 +76,10 @@ module.exports = {
assert(is.function(mw), `Middleware ${name} must be a function, but actual is ${inspect(mw)}`);
mw._name = name;
// middlewares support options.enable, options.ignore and options.match
- mw = wrapMiddleware(mw, options);
+ mw = wrapMiddleware(mw, {
+ ...options,
+ pathToRegexpModule: app.options.pathToRegexpModule,
+ });
if (mw) {
if (debug.enabled) {
// show mw debug log on every request
@@ -104,9 +107,11 @@ function wrapMiddleware(mw, options) {
mw = utils.middleware(mw);
// support options.match and options.ignore
- if (!options.match && !options.ignore) return mw;
- const match = pathMatching(options);
+ if (!options.match && !options.ignore) {
+ return mw;
+ }
+ const match = pathMatching(options);
const fn = (ctx, next) => {
if (!match(ctx)) return next();
return mw(ctx, next);
diff --git a/package.json b/package.json
index 7cdba82d..13f35f37 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
"scripts": {
"lint": "eslint .",
"test": "npm run lint -- --fix && npm run test-local",
- "test-local": "egg-bin test -p",
+ "test-local": "egg-bin test -p --full-trace",
"test-single": "egg-bin test",
"cov": "egg-bin cov -p",
"ci": "npm run lint && npm run cov",
@@ -23,7 +23,7 @@
},
"repository": {
"type": "git",
- "url": "git+https://github.com/eggjs/egg-core.git"
+ "url": "git+https://github.com/eggjs/core.git"
},
"keywords": [
"egg",
@@ -34,7 +34,7 @@
"bugs": {
"url": "https://github.com/eggjs/egg/issues"
},
- "homepage": "https://github.com/eggjs/egg-core#readme",
+ "homepage": "https://github.com/eggjs/core#readme",
"engines": {
"node": ">= 14.19.0"
},
@@ -53,17 +53,18 @@
"supertest": "^4.0.2",
"ts-node": "^10.9.1",
"typescript": "^4.9.4",
- "urllib": "^3.10.0"
+ "urllib": "^3.10.0",
+ "path-to-regexp-v8": "npm:path-to-regexp@8"
},
"dependencies": {
- "@eggjs/router": "^2.0.0",
+ "@eggjs/router": "^2.2.0",
"@types/depd": "^1.1.32",
"@types/koa": "^2.13.5",
"co": "^4.6.0",
"debug": "^4.1.1",
"depd": "^2.0.0",
"egg-logger": "^3.1.0",
- "egg-path-matching": "^1.0.1",
+ "egg-path-matching": "^1.2.0",
"extend2": "^1.0.0",
"gals": "^1.0.1",
"get-ready": "^2.0.1",
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/controller/async.js b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/async.js
new file mode 100644
index 00000000..68692fa7
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/async.js
@@ -0,0 +1,9 @@
+'use strict';
+
+module.exports = app => {
+ return class AsyncController extends app.Controller {
+ async index() {
+ this.ctx.body.push('async');
+ }
+ }
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/controller/comments.js b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/comments.js
new file mode 100644
index 00000000..8b8d928b
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/comments.js
@@ -0,0 +1,15 @@
+'use strict';
+
+// 测试 app.resources 遇到 controller 没有足够的 action 的场景
+
+exports.index = function* () {
+ this.body = 'index';
+};
+
+exports.new = function* () {
+ this.body = 'new';
+};
+
+exports.show = function* () {
+ this.body = 'show - ' + this.params.id;
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/controller/locals.js b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/locals.js
new file mode 100644
index 00000000..cced36fe
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/locals.js
@@ -0,0 +1,5 @@
+'use strict';
+
+exports.router = function* () {
+ yield this.render('locals/router.html');
+};
\ No newline at end of file
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/controller/members.js b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/members.js
new file mode 100644
index 00000000..013ceb8d
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/members.js
@@ -0,0 +1,19 @@
+'use strict';
+
+// 测试 app.resources 遇到 controller 没有足够的 action 的场景
+
+exports.index = function* () {
+ this.body = 'index';
+};
+
+exports.new = function* () {
+ this.body = 'new';
+};
+
+exports.show = function* () {
+ this.body = 'show - ' + this.params.id;
+};
+
+exports.delete = function* () {
+ this.body = `delete - ${this.params.id}`;
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/controller/middleware.js b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/middleware.js
new file mode 100644
index 00000000..d96c1c5b
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/middleware.js
@@ -0,0 +1,5 @@
+'use strict';
+
+module.exports = function* () {
+ this.body = [];
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/controller/package.js b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/package.js
new file mode 100644
index 00000000..b5b4fd64
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/package.js
@@ -0,0 +1,5 @@
+'use strict';
+
+exports.get = function* () {
+ this.body = this.params[0];
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/controller/posts.js b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/posts.js
new file mode 100644
index 00000000..6e140350
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/controller/posts.js
@@ -0,0 +1,29 @@
+'use strict';
+
+exports.index = function* () {
+ this.body = 'index';
+};
+
+exports.new = function* () {
+ this.body = 'new';
+};
+
+exports.create = function* () {
+ this.body = 'create';
+};
+
+exports.show = function* () {
+ this.body = 'show - ' + this.params.id;
+};
+
+exports.edit = function* () {
+ this.body = 'edit - ' + this.params.id;
+};
+
+exports.update = function* () {
+ this.body = 'update - ' + this.params.id;
+};
+
+exports.destroy = function* () {
+ this.body = 'destroy - ' + this.params.id;
+};
\ No newline at end of file
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/async.js b/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/async.js
new file mode 100644
index 00000000..fe2af8e5
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/async.js
@@ -0,0 +1,8 @@
+'use strict';
+
+module.exports = function() {
+ return async (ctx, next) => {
+ await next();
+ ctx.body.push('async');
+ };
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/common.js b/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/common.js
new file mode 100644
index 00000000..0a53e7d0
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/common.js
@@ -0,0 +1,9 @@
+'use strict';
+
+module.exports = function() {
+ return function(ctx, next) {
+ return next().then(() => {
+ ctx.body.push('common');
+ });
+ };
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/generator.js b/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/generator.js
new file mode 100644
index 00000000..957e26f0
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/generator.js
@@ -0,0 +1,8 @@
+'use strict';
+
+module.exports = function() {
+ return function*(next) {
+ yield next;
+ this.body.push('generator');
+ };
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/generator_both.js b/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/generator_both.js
new file mode 100644
index 00000000..3264b22b
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/middleware/generator_both.js
@@ -0,0 +1,10 @@
+'use strict';
+
+module.exports = function() {
+ return function*(next) {
+ this.body = [];
+ this.body.push('generator before');
+ yield next;
+ this.body.push('generator after');
+ };
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/router.js b/test/fixtures/router-app-with-pathToRegexpModule/app/router.js
new file mode 100644
index 00000000..49130821
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/router.js
@@ -0,0 +1,34 @@
+module.exports = function (app) {
+ const common = app.middlewares.common();
+ const asyncMw = app.middlewares.async();
+ const generator = app.middlewares.generator();
+ const generatorBoth = app.middlewares.generatorBoth();
+
+ app
+ .get('/locals/router', app.controller.locals.router)
+ .get('/members/index', 'members.index')
+ .delete('/members/delete/:id', 'members.delete')
+ .del('/members/del/:id', 'members.delete')
+ .resources('posts', '/posts', 'posts')
+ .resources('members', '/members', app.controller.members)
+ .resources('/comments', app.controller.comments)
+ // not work on path-to-regexp@8
+ // .get('comment_index', '/comments/:id?filter=', app.controller.comments.index)
+ .get('params', '/params/:a/:b', app.controller.locals.router)
+ .get('/middleware', common, asyncMw, generator, 'middleware')
+ .get('middleware', '/named_middleware', common, asyncMw, generator, 'middleware')
+ .get('/mix', generatorBoth , 'async.index')
+ .register('/comments', [ 'post' ] , app.controller.comments.new)
+ .register('/register_middleware', [ 'get' ], [ common, asyncMw, generator, 'middleware' ])
+ .redirect('/redirect', '/middleware', 302);
+
+ app.router
+ .get('/router_middleware', common, asyncMw, generator, 'middleware')
+ .redirect('/router_redirect', '/middleware');
+
+ // not work on path-to-regexp@8
+ // app.get('packages', /^\/packages\/(.*)/, 'package.get');
+
+ app.get([ '/url1', '/url2' ], 'members.index')
+ app.get([ '/urlm1', '/urlm2' ], common, asyncMw, generator, 'middleware')
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/app/views/locals/router.html b/test/fixtures/router-app-with-pathToRegexpModule/app/views/locals/router.html
new file mode 100644
index 00000000..0006527d
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/app/views/locals/router.html
@@ -0,0 +1 @@
+posts: /posts
\ No newline at end of file
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/config/config.default.js b/test/fixtures/router-app-with-pathToRegexpModule/config/config.default.js
new file mode 100644
index 00000000..166a3213
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/config/config.default.js
@@ -0,0 +1,9 @@
+'use strict';
+
+exports.keys = 'my';
+
+exports.security = {
+ csrf: {
+ enable: false,
+ },
+};
diff --git a/test/fixtures/router-app-with-pathToRegexpModule/package.json b/test/fixtures/router-app-with-pathToRegexpModule/package.json
new file mode 100644
index 00000000..85a85027
--- /dev/null
+++ b/test/fixtures/router-app-with-pathToRegexpModule/package.json
@@ -0,0 +1,3 @@
+{
+ "name": "router-app-with-pathToRegexpModule"
+}
diff --git a/test/utils/router-with-pathToRegexpModule.test.js b/test/utils/router-with-pathToRegexpModule.test.js
new file mode 100644
index 00000000..79d302f1
--- /dev/null
+++ b/test/utils/router-with-pathToRegexpModule.test.js
@@ -0,0 +1,346 @@
+const assert = require('assert');
+const request = require('supertest');
+const utils = require('../utils');
+
+describe('test/utils/router-with-pathToRegexpModule.test.js', () => {
+ let app;
+ before(() => {
+ app = utils.createApp('router-app-with-pathToRegexpModule', {
+ pathToRegexpModule: require.resolve('path-to-regexp-v8'),
+ });
+ app.loader.loadAll();
+ return app.ready();
+ });
+ after(() => app.close());
+
+ describe('router.resources', () => {
+ describe('normal', () => {
+ it('should GET /posts', () => {
+ return request(app.callback())
+ .get('/posts')
+ .expect(200)
+ .expect('index');
+ });
+
+ it('should GET /posts/new', () => {
+ return request(app.callback())
+ .get('/posts/new')
+ .expect(200)
+ .expect('new');
+ });
+
+ it('should POST /posts', () => {
+ return request(app.callback())
+ .post('/posts')
+ .expect(200)
+ .expect('create');
+ });
+
+ it('should GET /posts/:id', () => {
+ return request(app.callback())
+ .get('/posts/123')
+ .expect(200)
+ .expect('show - 123');
+ });
+
+ it('should GET /posts/:id/edit', () => {
+ return request(app.callback())
+ .get('/posts/123/edit')
+ .expect(200)
+ .expect('edit - 123');
+ });
+
+ it('should PATCH /posts/:id', () => {
+ return request(app.callback())
+ .patch('/posts/123')
+ .expect(200)
+ .expect('update - 123');
+ });
+
+ it('should PUT /posts/:id', () => {
+ return request(app.callback())
+ .put('/posts/123')
+ .expect(200)
+ .expect('update - 123');
+ });
+
+ it('should DELETE /posts/:id', () => {
+ return request(app.callback())
+ .delete('/posts/123')
+ .expect(200)
+ .expect('destroy - 123');
+ });
+ });
+
+ describe('controller url', () => {
+ it('should GET /members', () => {
+ return request(app.callback())
+ .get('/members')
+ .expect(200)
+ .expect('index');
+ });
+
+ it('should GET /members/index', () => {
+ return request(app.callback())
+ .get('/members/index')
+ .expect(200)
+ .expect('index');
+ });
+
+ it('should GET /members/new', () => {
+ return request(app.callback())
+ .get('/members/new')
+ .expect(200)
+ .expect('new');
+ });
+
+ it('should GET /members/:id', () => {
+ return request(app.callback())
+ .get('/members/1231')
+ .expect(200)
+ .expect('show - 1231');
+ });
+
+ it('should POST /members', () => {
+ return request(app.callback())
+ .post('/members')
+ .expect(404);
+ });
+
+ it('should PUT /members/:id', () => {
+ return request(app.callback())
+ .put('/members/1231')
+ .expect(404);
+ });
+
+ // not work on path-to-regexp@8
+ it.skip('should GET /POSTS', () => {
+ return request(app.callback())
+ .get('/POSTS')
+ .expect(404);
+ });
+
+ it('should GET /members/delete/:id', () => {
+ return request(app.callback())
+ .delete('/members/delete/1')
+ .expect(200)
+ .expect('delete - 1');
+ });
+
+ it('should GET /members/del/:id', () => {
+ return request(app.callback())
+ .del('/members/del/1')
+ .expect(200)
+ .expect('delete - 1');
+ });
+
+ // not work on path-to-regexp@8
+ it.skip('should GET /packages/(.*)', () => {
+ return request(app.callback())
+ .get('/packages/urllib')
+ .expect('urllib');
+ });
+ });
+
+ describe('no name', () => {
+ it('should GET /comments', () => {
+ return request(app.callback())
+ .get('/comments')
+ .expect('index')
+ .expect(200);
+ });
+
+ it('should POST /comments', () => {
+ return request(app.callback())
+ .post('/comments')
+ .expect('new')
+ .expect(200);
+ });
+ });
+
+ describe('async controller', () => {
+ it('should execute by the correct order', () => {
+ return request(app.callback())
+ .get('/mix')
+ .expect([ 'generator before', 'async', 'generator after' ])
+ .expect(200);
+ });
+ });
+ });
+
+ describe('router.url', () => {
+ it('should work', () => {
+ assert(app.url('posts') === '/posts');
+
+ assert(app.router.url('posts') === '/posts');
+ assert(app.router.url('members') === '/members');
+ assert(app.router.url('post', { id: 1 }) === '/posts/1');
+ assert(app.router.url('member', { id: 1 }) === '/members/1');
+ assert(app.router.url('new_post') === '/posts/new');
+ assert(app.router.url('new_member') === '/members/new');
+ assert(app.router.url('edit_post', { id: 1 }) === '/posts/1/edit');
+ assert(app.router.url('params', { a: 1, b: 2 }) === '/params/1/2');
+ // no match params
+ assert(app.router.url('edit_post', {}) === '/posts/:id/edit');
+ assert(app.router.url('noname') === '');
+ // assert(app.router.url('comment_index', { id: 1, a: 1 }) === '/comments/1?filter=&a=1');
+ });
+
+ it('should work with unknow params', () => {
+ assert(app.router.url('posts', { name: 'foo', page: 2 }) === '/posts?name=foo&page=2');
+ assert(app.router.url('posts', { name: 'foo&?', page: 2 }) === '/posts?name=foo%26%3F&page=2');
+ assert(app.router.url('edit_post', { id: 10, page: 2 }) === '/posts/10/edit?page=2');
+ assert(app.router.url('edit_post', { i: 2, id: 10 }) === '/posts/10/edit?i=2');
+ assert(app.router.url('edit_post', { id: 10, page: 2, tags: [ 'chair', 'develop' ] }) ===
+ '/posts/10/edit?page=2&tags=chair&tags=develop');
+ assert(app.router.url('edit_post', { id: [ 10 ], page: [ 2 ], tags: [ 'chair', 'develop' ] }) ===
+ '/posts/10/edit?page=2&tags=chair&tags=develop');
+ assert(app.router.url('edit_post', { id: [ 10, 11 ], page: [ 2 ], tags: [ 'chair', 'develop' ] }) ===
+ '/posts/10/edit?page=2&tags=chair&tags=develop');
+ });
+
+ it.skip('should not support regular url', () => {
+ assert.throws(() => {
+ app.router.url('packages', [ 'urllib' ]);
+ }, 'Can\'t get the url for regExp /^\/packages\/(.*)/ for by name \'posts\'');
+ });
+ });
+
+ describe('router.pathFor', () => {
+ it('should work', () => {
+ assert(app.router.pathFor('posts') === '/posts');
+ });
+ });
+
+ describe('router.method', () => {
+ it('router method include HEAD', () => {
+ assert(app.router.methods.includes('HEAD'));
+ });
+ });
+
+ describe('router middleware', () => {
+ it('should support all kinds of middlewares', () => {
+ return request(app.callback())
+ .get('/middleware')
+ .expect(200)
+ .expect([ 'generator', 'async', 'common' ]);
+ });
+
+ it('should support all kinds of middlewares with name', () => {
+ return request(app.callback())
+ .get('/named_middleware')
+ .expect(200)
+ .expect([ 'generator', 'async', 'common' ]);
+ });
+
+ it('should support all kinds of middlewares with register', () => {
+ return request(app.callback())
+ .get('/register_middleware')
+ .expect(200)
+ .expect([ 'generator', 'async', 'common' ]);
+ });
+
+ it('should app.router support all kinds of middlewares', () => {
+ return request(app.callback())
+ .get('/router_middleware')
+ .expect(200)
+ .expect([ 'generator', 'async', 'common' ]);
+ });
+ });
+
+ describe('redirect', () => {
+ it('should app.redirect to target', () => {
+ return request(app.callback())
+ .get('/redirect')
+ .expect(302)
+ .expect('location', '/middleware');
+ });
+
+ it('should app.router.redirect to target', () => {
+ return request(app.callback())
+ .get('/router_redirect')
+ .expect(301)
+ .expect('location', '/middleware');
+ });
+ });
+
+ describe('controller mutli url', () => {
+ it('should GET /url1', () => {
+ return request(app.callback())
+ .get('/url1')
+ .expect(200)
+ .expect('index');
+ });
+ it('should GET /url2', () => {
+ return request(app.callback())
+ .get('/url2')
+ .expect(200)
+ .expect('index');
+ });
+ it('use middlewares /urlm1', () => {
+ return request(app.callback())
+ .get('/urlm1')
+ .expect(200)
+ .expect([ 'generator', 'async', 'common' ]);
+ });
+ it('use middlewares /urlm2', () => {
+ return request(app.callback())
+ .get('/urlm2')
+ .expect(200)
+ .expect([ 'generator', 'async', 'common' ]);
+ });
+ });
+
+ describe('controller not exist', () => {
+ it('should check when app.router.VERB', () => {
+ try {
+ app.router.get('/test', app.controller.not_exist);
+ throw new Error('should not run here');
+ } catch (err) {
+ assert(err.message.includes('controller not exists'));
+ }
+ });
+
+ it('should check when app.router.VERB with controller string', () => {
+ try {
+ app.get('/hello', 'not.exist.controller');
+ throw new Error('should not run here');
+ } catch (err) {
+ assert(err.message.includes('controller \'not.exist.controller\' not exists'));
+ }
+ });
+
+ it('should check when app.router.resources', () => {
+ try {
+ app.router.resources('/test', app.controller.not_exist);
+ throw new Error('should not run here');
+ } catch (err) {
+ assert(err.message.includes('controller not exists'));
+ }
+ });
+
+ it('should check when app.router.resources with controller string', () => {
+ try {
+ app.router.resources('/test', 'not.exist.controller');
+ throw new Error('should not run here');
+ } catch (err) {
+ assert(err.message.includes('controller \'not.exist.controller\' not exists'));
+ }
+ });
+ });
+
+ describe('router middleware', () => {
+ before(() => {
+ app = utils.createApp('router-in-app');
+ app.loader.loadAll();
+ return app.ready();
+ });
+
+ it('should always load router middleware at last', () => {
+ return request(app.callback())
+ .get('/')
+ .expect(200)
+ .expect('foo');
+ });
+ });
+});