@contrast/route-coverage 1.23.1 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/install/fastify.js +117 -67
- package/lib/install/fastify.test.js +186 -165
- package/lib/utils/methods.js +2 -2
- package/package.json +7 -7
package/lib/install/fastify.js
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
|
-
const {
|
|
18
|
-
const {
|
|
17
|
+
const { getFastifyMethods } = require('../utils/methods');
|
|
18
|
+
const { StringPrototypeToLowerCase } = require('@contrast/common');
|
|
19
19
|
const { patchType } = require('./../utils/route-info');
|
|
20
20
|
|
|
21
21
|
// Spec: https://contrast.atlassian.net/wiki/spaces/NOD/pages/3454861621/Node.js+Agent+Route+Signatures#Fastify
|
|
@@ -28,19 +28,14 @@ module.exports = function init(core) {
|
|
|
28
28
|
We need a way to keep track of which routes were fully declared using .route
|
|
29
29
|
So, we instrument the route method below and add identifying info to this array
|
|
30
30
|
*/
|
|
31
|
-
const fullyDeclaredRoutes = [];
|
|
32
31
|
const { patcher, depHooks, routeCoverage } = core;
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
fullyDeclaredRoutes.push(method + url);
|
|
38
|
-
if (method === 'GET') fullyDeclaredRoutes.push(`HEAD${url}`);
|
|
39
|
-
}
|
|
33
|
+
function getPrefix(route) {
|
|
34
|
+
const kRoutePrefix = Object.getOwnPropertySymbols(route).find((s) => s.description === 'fastify.routePrefix');
|
|
35
|
+
return route?.[kRoutePrefix];
|
|
40
36
|
}
|
|
41
37
|
|
|
42
|
-
function createRouteInfo(method, url,
|
|
43
|
-
const fullyDeclared = isFullyDeclared(method, routePath);
|
|
38
|
+
function createRouteInfo(method, url, fullyDeclared) {
|
|
44
39
|
method = StringPrototypeToLowerCase.call(method);
|
|
45
40
|
|
|
46
41
|
const signature = fullyDeclared
|
|
@@ -57,67 +52,122 @@ module.exports = function init(core) {
|
|
|
57
52
|
return routeInfo;
|
|
58
53
|
}
|
|
59
54
|
|
|
55
|
+
function patchHandler(route, handle, routeInfo) {
|
|
56
|
+
const pre = ({ args }) => {
|
|
57
|
+
const [req] = args;
|
|
58
|
+
const method = StringPrototypeToLowerCase.call(req.raw?.method);
|
|
59
|
+
const [url] = req.url.split(/\?/);
|
|
60
|
+
routeCoverage.observe({ ...routeInfo, url, method });
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const name = `fastify.route.${handle}`;
|
|
64
|
+
if (route[handle]) {
|
|
65
|
+
patcher.patch(route, handle, {
|
|
66
|
+
name,
|
|
67
|
+
patchType,
|
|
68
|
+
pre
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
const idx = handle === 'options' ? 2 : handle === 'handler' ? 3 : null;
|
|
72
|
+
if (idx) route[idx] = patcher.patch(route[idx], {
|
|
73
|
+
name,
|
|
74
|
+
patchType,
|
|
75
|
+
pre
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function discoverAndPatch(method, path, handler, handle, methods, fullyDeclared) {
|
|
81
|
+
if (Array.isArray(method)) {
|
|
82
|
+
// If all valid methods are included in `method` then .all shorthand was most likely used
|
|
83
|
+
if (methods.every(m => method.includes(m))) {
|
|
84
|
+
const routeInfo = createRouteInfo('all', path, fullyDeclared);
|
|
85
|
+
routeCoverage.discover(routeInfo);
|
|
86
|
+
patchHandler(handler, handle, routeInfo);
|
|
87
|
+
} else {
|
|
88
|
+
method.forEach((verb) => {
|
|
89
|
+
const routeInfo = createRouteInfo(verb, path, fullyDeclared);
|
|
90
|
+
routeCoverage.discover(routeInfo);
|
|
91
|
+
patchHandler(handler, handle, routeInfo);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
const routeInfo = createRouteInfo(method, path, fullyDeclared);
|
|
96
|
+
routeCoverage.discover(routeInfo);
|
|
97
|
+
patchHandler(handler, handle, routeInfo);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
60
101
|
return core.routeCoverage.fastify = {
|
|
61
102
|
install() {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
103
|
+
/**
|
|
104
|
+
* There are some subtle differences between fastify minor versions the instrumentation must account for
|
|
105
|
+
* >=3 <4.1.0 the route options are passed in as regular args i.e. route(method, url, options, handler)
|
|
106
|
+
* and prepareRoute(method, url, options, handler)
|
|
107
|
+
* >= 4.1.0 the route options are passed in as an object i.e. route({ method, url, options, handler })
|
|
108
|
+
* and prepareRoute({ options: { method, url, options, handler }})
|
|
109
|
+
*/
|
|
110
|
+
[
|
|
111
|
+
{ version: '>=3 <4.1.0', routeObj: false },
|
|
112
|
+
{ version: '>=4.1.0 <4.4.0', routeObj: true },
|
|
113
|
+
{ version: '>=4.4.0', routeObj: true }
|
|
114
|
+
].forEach(({ version, routeObj }) => {
|
|
115
|
+
// See ../utils/methods
|
|
116
|
+
// Using .all shorthand uses all valid methods but those change after version 4.4.0
|
|
117
|
+
const FASTIFY_METHODS = getFastifyMethods(version);
|
|
118
|
+
depHooks.resolve({ name: 'fastify', version, file: 'lib/route.js' }, (Route) => {
|
|
119
|
+
patcher.patch(Route, 'buildRouting', {
|
|
120
|
+
name: 'fastify.Route.buildRouting',
|
|
69
121
|
patchType,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (!method || !url || !routePath || !isString(routePath)) return;
|
|
88
|
-
|
|
89
|
-
let routeInfo;
|
|
90
|
-
const FASTIFY_METHODS = getFastifyMethods(server.version);
|
|
91
|
-
if (Array.isArray(method)) {
|
|
92
|
-
// If a route was defined using .all this method property will be an
|
|
93
|
-
// array of all methods supported by Fastify
|
|
94
|
-
if (FASTIFY_METHODS.every(m => method.includes(m))) {
|
|
95
|
-
routeInfo = createRouteInfo('all', url, routePath);
|
|
96
|
-
routeCoverage.discover(routeInfo);
|
|
97
|
-
} else {
|
|
98
|
-
method.forEach((verb) => {
|
|
99
|
-
routeInfo = createRouteInfo(verb, url, routePath);
|
|
100
|
-
routeCoverage.discover(routeInfo);
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
routeInfo = createRouteInfo(method, url, routePath);
|
|
105
|
-
routeCoverage.discover(routeInfo);
|
|
106
|
-
}
|
|
122
|
+
post(data) {
|
|
123
|
+
|
|
124
|
+
// Handles routes defined through fastify.<method> shorthand
|
|
125
|
+
patcher.patch(data.result, 'prepareRoute', {
|
|
126
|
+
name: 'prepareRoute',
|
|
127
|
+
patchType,
|
|
128
|
+
pre(data) {
|
|
129
|
+
if (!data.args.length) return;
|
|
130
|
+
|
|
131
|
+
let method, url, options, handler;
|
|
132
|
+
if (routeObj) {
|
|
133
|
+
[{ method, url, options, handler }] = data.args;
|
|
134
|
+
} else {
|
|
135
|
+
[method, url, options, handler] = data.args;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!method || !url || !(options || handler)) return;
|
|
107
139
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
140
|
+
const prefix = getPrefix(data.obj);
|
|
141
|
+
const path = prefix ? prefix + url : url;
|
|
142
|
+
|
|
143
|
+
// See lib/route.js: prepareRoute
|
|
144
|
+
let handle = 'handler';
|
|
145
|
+
if (!handler && typeof options === 'function') handle = 'options';
|
|
146
|
+
|
|
147
|
+
discoverAndPatch(method, path, routeObj ? data.args[0] : data.args, handle, FASTIFY_METHODS, false);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Handles routes defined fully fastify.route({})
|
|
152
|
+
patcher.patch(data.result, 'route', {
|
|
153
|
+
name: 'route',
|
|
154
|
+
patchType,
|
|
155
|
+
pre(data) {
|
|
156
|
+
|
|
157
|
+
if (!data.args.length) return;
|
|
158
|
+
const routeArgs = routeObj ? data.args[0]?.options : data.args[0];
|
|
159
|
+
const { url, method, handler } = routeArgs;
|
|
160
|
+
if (!method || !url || !handler) return;
|
|
161
|
+
|
|
162
|
+
const prefix = getPrefix(data.obj);
|
|
163
|
+
const path = prefix ? prefix + url : url;
|
|
164
|
+
discoverAndPatch(method, path, routeArgs, 'handler', FASTIFY_METHODS, true);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
118
168
|
});
|
|
119
|
-
}
|
|
120
|
-
})
|
|
169
|
+
});
|
|
170
|
+
});
|
|
121
171
|
}
|
|
122
172
|
};
|
|
123
173
|
};
|
|
@@ -7,191 +7,212 @@ const patcher = require('@contrast/patcher');
|
|
|
7
7
|
const mocks = require('@contrast/test/mocks');
|
|
8
8
|
const { getFastifyMethods } = require('../utils/methods');
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
core
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
10
|
+
[
|
|
11
|
+
{ version: '>=3 <4.1.0', routeObj: false },
|
|
12
|
+
{ version: '>=4.1.0 <4.4.0', routeObj: true },
|
|
13
|
+
{ version: '>=4.4.0', routeObj: true }
|
|
14
|
+
].forEach(({ version, routeObj }) => {
|
|
15
|
+
describe(`route-coverage fastify (${version})`, function () {
|
|
16
|
+
const FASTIFY_METHODS = getFastifyMethods(version);
|
|
17
|
+
let core, RouteMock, framework, routing, fn;
|
|
18
|
+
|
|
19
|
+
function routeOptions(options, fullyDeclared, routeObj) {
|
|
20
|
+
if (fullyDeclared && routeObj) {
|
|
21
|
+
return [{ options }];
|
|
22
|
+
} else if ((fullyDeclared && !routeObj) || (!fullyDeclared && routeObj)) {
|
|
23
|
+
return [options];
|
|
24
|
+
} else if (!fullyDeclared && !routeObj) {
|
|
25
|
+
return Object.values(options);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
beforeEach(function () {
|
|
30
|
+
core = mocks.core();
|
|
31
|
+
core.logger = mocks.logger();
|
|
32
|
+
core.routeCoverage = mocks.routeCoverage();
|
|
33
|
+
core.scopes = scopes(core);
|
|
34
|
+
core.depHooks = mocks.depHooks();
|
|
35
|
+
core.patcher = patcher(core);
|
|
36
|
+
sinon.spy(core.patcher, 'patch');
|
|
37
|
+
|
|
38
|
+
RouteMock = {
|
|
39
|
+
buildRouting: () => ({
|
|
40
|
+
prepareRoute: sinon.stub(),
|
|
41
|
+
route: sinon.stub()
|
|
42
|
+
})
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
framework = 'fastify';
|
|
46
|
+
core.depHooks.resolve
|
|
47
|
+
.withArgs({ name: 'fastify', version, file: 'lib/route.js' })
|
|
48
|
+
.yields(RouteMock);
|
|
49
|
+
|
|
50
|
+
require('./fastify')(core).install();
|
|
51
|
+
|
|
52
|
+
routing = RouteMock.buildRouting();
|
|
53
|
+
fn = sinon.stub();
|
|
31
54
|
});
|
|
32
55
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
59
|
-
signature: "fastify.get('/test/route', [Function])",
|
|
60
|
-
url: '/test/route',
|
|
61
|
-
normalizedUrl: '/test/route',
|
|
62
|
-
method: 'get',
|
|
63
|
-
framework
|
|
56
|
+
[
|
|
57
|
+
{ method: 'prepareRoute', fullyDefined: false },
|
|
58
|
+
{ method: 'route', fullyDefined: true },
|
|
59
|
+
].forEach(({ method, fullyDefined }) => {
|
|
60
|
+
describe(`.${method} base cases`, function() {
|
|
61
|
+
it('skips instrumenting if nothing is provided', function () {
|
|
62
|
+
routing[method]();
|
|
63
|
+
expect(core.routeCoverage.discover).not.to.have.been.called;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('skips instrumenting if there is no method provided', function () {
|
|
67
|
+
routing[method](...routeOptions({ url: '/test/route', handler: fn }, fullyDefined, routeObj));
|
|
68
|
+
expect(core.routeCoverage.discover).not.to.have.been.called;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('skips instrumenting if there is no url provided', function () {
|
|
72
|
+
routing[method](...routeOptions({ method: 'GET', handler: fn }, fullyDefined, routeObj));
|
|
73
|
+
expect(core.routeCoverage.discover).not.to.have.been.called;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('skips instrumenting if there is no handler is provided', function () {
|
|
77
|
+
routing[method](...routeOptions({ method: 'GET', url: '/test/route' }, fullyDefined, routeObj));
|
|
78
|
+
expect(core.routeCoverage.discover).not.to.have.been.called;
|
|
79
|
+
});
|
|
80
|
+
});
|
|
64
81
|
});
|
|
65
|
-
expect(core.routeCoverage.discover).to.have.been.called;
|
|
66
|
-
expect(core.routeCoverage.discover).to.have.callCount(1);
|
|
67
|
-
});
|
|
68
82
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
framework
|
|
83
|
+
it('discovers a route with a single method', function () {
|
|
84
|
+
routing.prepareRoute(...routeOptions({ method: 'GET', url: '/test/route', handler: fn }, false, routeObj));
|
|
85
|
+
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
86
|
+
signature: "fastify.get('/test/route', [Function])",
|
|
87
|
+
url: '/test/route',
|
|
88
|
+
normalizedUrl: '/test/route',
|
|
89
|
+
method: 'get',
|
|
90
|
+
framework
|
|
91
|
+
});
|
|
92
|
+
expect(core.routeCoverage.discover).to.have.been.called;
|
|
93
|
+
expect(core.routeCoverage.discover).to.have.callCount(1);
|
|
81
94
|
});
|
|
82
|
-
expect(core.routeCoverage.discover).to.have.been.called;
|
|
83
|
-
expect(core.routeCoverage.discover).to.have.callCount(1);
|
|
84
|
-
});
|
|
85
95
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
method:
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
it('discovers a route with a prefixed path', function () {
|
|
97
|
+
routing[Symbol('fastify.routePrefix')] = '/prefix';
|
|
98
|
+
routing.prepareRoute(...routeOptions({ method: 'GET', url: '/test/route', handler: fn }, false, routeObj));
|
|
99
|
+
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
100
|
+
signature: "fastify.get('/prefix/test/route', [Function])",
|
|
101
|
+
url: '/prefix/test/route',
|
|
102
|
+
normalizedUrl: '/prefix/test/route',
|
|
103
|
+
method: 'get',
|
|
104
|
+
framework
|
|
105
|
+
});
|
|
106
|
+
expect(core.routeCoverage.discover).to.have.been.called;
|
|
107
|
+
expect(core.routeCoverage.discover).to.have.callCount(1);
|
|
91
108
|
});
|
|
92
109
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
url: '/test/route',
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
110
|
+
it('discovers a fully declared (.route) with a prefixed path', function () {
|
|
111
|
+
routing[Symbol('fastify.routePrefix')] = '/prefix';
|
|
112
|
+
routing.route(...routeOptions({ method: 'GET', url: '/test/route', handler: fn }, true, routeObj));
|
|
113
|
+
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
114
|
+
signature: "fastify.route({ method: 'get', url: '/prefix/test/route', handler: [Function] })",
|
|
115
|
+
url: '/prefix/test/route',
|
|
116
|
+
normalizedUrl: '/prefix/test/route',
|
|
117
|
+
method: 'get',
|
|
118
|
+
framework
|
|
119
|
+
});
|
|
120
|
+
expect(core.routeCoverage.discover).to.have.been.called;
|
|
121
|
+
expect(core.routeCoverage.discover).to.have.callCount(1);
|
|
99
122
|
});
|
|
100
123
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
124
|
+
it('discovers a fully declared (.route) route with a single method', function () {
|
|
125
|
+
routing.route(...routeOptions({ method: 'GET', url: '/test/route', handler: fn }, true, routeObj));
|
|
126
|
+
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
127
|
+
signature: "fastify.route({ method: 'get', url: '/test/route', handler: [Function] })",
|
|
128
|
+
url: '/test/route',
|
|
129
|
+
normalizedUrl: '/test/route',
|
|
130
|
+
method: 'get',
|
|
131
|
+
framework
|
|
132
|
+
});
|
|
133
|
+
expect(core.routeCoverage.discover).to.have.been.called;
|
|
134
|
+
expect(core.routeCoverage.discover).to.have.callCount(1);
|
|
107
135
|
});
|
|
108
136
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
137
|
+
it('discovers a route with multiple methods', function () {
|
|
138
|
+
routing.prepareRoute(...routeOptions({ method: ['GET', 'POST'], url: '/test/route', handler: fn }, false, routeObj));
|
|
139
|
+
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
140
|
+
signature: "fastify.get('/test/route', [Function])",
|
|
141
|
+
url: '/test/route',
|
|
142
|
+
normalizedUrl: '/test/route',
|
|
143
|
+
method: 'get',
|
|
144
|
+
framework
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
148
|
+
signature: "fastify.post('/test/route', [Function])",
|
|
149
|
+
url: '/test/route',
|
|
150
|
+
normalizedUrl: '/test/route',
|
|
151
|
+
method: 'post',
|
|
152
|
+
framework
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(core.routeCoverage.discover).to.have.callCount(2);
|
|
118
156
|
});
|
|
119
157
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
158
|
+
it('discovers a route with all methods', function () {
|
|
159
|
+
routing.prepareRoute(...routeOptions({ method: FASTIFY_METHODS, url: '/test/route', handler: fn }, false, routeObj));
|
|
160
|
+
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
161
|
+
signature: "fastify.all('/test/route', [Function])",
|
|
162
|
+
url: '/test/route',
|
|
163
|
+
normalizedUrl: '/test/route',
|
|
164
|
+
method: 'all',
|
|
165
|
+
framework
|
|
166
|
+
});
|
|
126
167
|
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('discovers a fully declared route (.route) with multiple methods', function () {
|
|
130
|
-
serverMock.route({ method: ['GET', 'POST'], url: '/test/route' });
|
|
131
168
|
|
|
132
|
-
|
|
133
|
-
method: ['GET', 'POST'],
|
|
134
|
-
|
|
135
|
-
|
|
169
|
+
it('discovers a fully declared route (.route) with multiple methods', function () {
|
|
170
|
+
routing.route(...routeOptions({ method: ['GET', 'POST'], url: '/test/route', handler: fn }, true, routeObj));
|
|
171
|
+
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
172
|
+
signature: "fastify.route({ method: 'get', url: '/test/route', handler: [Function] })",
|
|
173
|
+
url: '/test/route',
|
|
174
|
+
normalizedUrl: '/test/route',
|
|
175
|
+
method: 'get',
|
|
176
|
+
framework
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(core.routeCoverage.discover).to.have.been.calledWith({
|
|
180
|
+
signature: "fastify.route({ method: 'post', url: '/test/route', handler: [Function] })",
|
|
181
|
+
url: '/test/route',
|
|
182
|
+
normalizedUrl: '/test/route',
|
|
183
|
+
method: 'post',
|
|
184
|
+
framework
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
expect(core.routeCoverage.discover).to.have.callCount(2);
|
|
136
188
|
});
|
|
137
189
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
method: '
|
|
143
|
-
|
|
190
|
+
it('observes a route when the route handler is called', function () {
|
|
191
|
+
routing.prepareRoute(...routeOptions({ method: 'GET', url: '/test/route', handler: fn }, false, routeObj));
|
|
192
|
+
const patchedFn = core.patcher.patch.getCall(3).returnValue;
|
|
193
|
+
const handler = routeObj ? patchedFn.handler : patchedFn;
|
|
194
|
+
handler({ raw: { method: 'GET' }, url: '/test/route' });
|
|
195
|
+
expect(core.routeCoverage.observe).to.have.been.calledWith({
|
|
196
|
+
signature: "fastify.get('/test/route', [Function])",
|
|
197
|
+
url: '/test/route',
|
|
198
|
+
method: 'get',
|
|
199
|
+
normalizedUrl: '/test/route',
|
|
200
|
+
framework: 'fastify'
|
|
201
|
+
});
|
|
144
202
|
});
|
|
145
203
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
method: '
|
|
151
|
-
|
|
204
|
+
it('removes query string from url before reporting observation', function () {
|
|
205
|
+
routing.prepareRoute(...routeOptions({ method: 'GET', url: '/test/route', handler: fn }, false, routeObj));
|
|
206
|
+
const patchedFn = core.patcher.patch.getCall(3).returnValue;
|
|
207
|
+
const handler = routeObj ? patchedFn.handler : patchedFn;
|
|
208
|
+
handler({ raw: { method: 'GET' }, url: '/test/route' });
|
|
209
|
+
expect(core.routeCoverage.observe).to.have.been.calledWith({
|
|
210
|
+
signature: "fastify.get('/test/route', [Function])",
|
|
211
|
+
url: '/test/route',
|
|
212
|
+
method: 'get',
|
|
213
|
+
normalizedUrl: '/test/route',
|
|
214
|
+
framework: 'fastify'
|
|
215
|
+
});
|
|
152
216
|
});
|
|
153
|
-
|
|
154
|
-
expect(core.routeCoverage.discover).to.have.callCount(2);
|
|
155
217
|
});
|
|
156
|
-
|
|
157
|
-
it('observes a route when the route handler is called', function () {
|
|
158
|
-
const routeOptions = {
|
|
159
|
-
method: 'GET',
|
|
160
|
-
url: '/test/route',
|
|
161
|
-
routePath: '/test/route',
|
|
162
|
-
handler: sinon.stub(),
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
serverMock.addHook.withArgs('onRoute').yield(routeOptions);
|
|
166
|
-
routeOptions.handler({ raw: { method: 'GET' }, url: '/test/route' });
|
|
167
|
-
|
|
168
|
-
expect(core.routeCoverage.observe).to.have.been.calledWith({
|
|
169
|
-
signature: "fastify.get('/test/route', [Function])",
|
|
170
|
-
url: '/test/route',
|
|
171
|
-
method: 'get',
|
|
172
|
-
normalizedUrl: '/test/route',
|
|
173
|
-
framework: 'fastify'
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('removes query string from url before reporting observation', function () {
|
|
178
|
-
const routeOptions = {
|
|
179
|
-
method: 'GET',
|
|
180
|
-
url: '/test/route',
|
|
181
|
-
routePath: '/test/route',
|
|
182
|
-
handler: sinon.stub(),
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
serverMock.addHook.withArgs('onRoute').yield(routeOptions);
|
|
186
|
-
routeOptions.handler({ raw: { method: 'GET' }, url: '/test/route?input=foo' });
|
|
187
|
-
|
|
188
|
-
expect(core.routeCoverage.observe).to.have.been.calledWith({
|
|
189
|
-
signature: "fastify.get('/test/route', [Function])",
|
|
190
|
-
url: '/test/route',
|
|
191
|
-
method: 'get',
|
|
192
|
-
normalizedUrl: '/test/route',
|
|
193
|
-
framework: 'fastify'
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
218
|
});
|
package/lib/utils/methods.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
const semver = require('semver');
|
|
19
19
|
const { METHODS } = require('http');
|
|
20
20
|
|
|
21
|
-
function getFastifyMethods(
|
|
21
|
+
function getFastifyMethods(range) {
|
|
22
22
|
return [
|
|
23
23
|
'DELETE',
|
|
24
24
|
'GET',
|
|
@@ -27,7 +27,7 @@ function getFastifyMethods(version) {
|
|
|
27
27
|
'POST',
|
|
28
28
|
'PUT',
|
|
29
29
|
'OPTIONS',
|
|
30
|
-
...semver.
|
|
30
|
+
...semver.subset(range, '>=4.4.0') ?
|
|
31
31
|
[
|
|
32
32
|
'PROPFIND',
|
|
33
33
|
'PROPPATCH',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/route-coverage",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"description": "Handles route discovery and observation",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"test": "../scripts/test.sh"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@contrast/common": "1.
|
|
21
|
-
"@contrast/config": "1.
|
|
22
|
-
"@contrast/dep-hooks": "1.
|
|
20
|
+
"@contrast/common": "1.25.0",
|
|
21
|
+
"@contrast/config": "1.32.0",
|
|
22
|
+
"@contrast/dep-hooks": "1.4.0",
|
|
23
23
|
"@contrast/fn-inspect": "^4.3.0",
|
|
24
|
-
"@contrast/logger": "1.
|
|
25
|
-
"@contrast/patcher": "1.
|
|
26
|
-
"@contrast/scopes": "1.
|
|
24
|
+
"@contrast/logger": "1.9.0",
|
|
25
|
+
"@contrast/patcher": "1.8.0",
|
|
26
|
+
"@contrast/scopes": "1.5.0"
|
|
27
27
|
}
|
|
28
28
|
}
|