Skip to content

Commit e117960

Browse files
Achieve 100% test coverage (#349)
* test: Router module integration test: findMyWay.findRoute should also trows an error when wildcard is not the last character test: does not find the route if maxParamLength is exceeded refactor: make integration test more compliant with the existing code base test: cover uncovered constrainer.js test cases test: safeDecodeURIComponent should replace %3x to null for every x that is not a valid lowchar test: SemVerStore version should be a string test: httpMethodStrategy storage handles set and get operations correctly test: case insensitive static routes of level 1 for FindMyWay.findRoute test: findRoute normalizes wildcard patterns to require leading slash refactor: make tests more consistants with the existing test: should return null if no wildchar child Date: Tue Feb 20 14:10:18 2024 +0100 Achieves 100% test coverage * fix: add proxyquire to dev dependencies * test: cover uncovered branches in index.js * fix: revert 'if (nextCharCode === 58)' stmt to one line * fix: remove useless parametric node kind check * fix: if it is a wildchar node, it has a child * fix: a wildcard route created via the router api necessarily has a pattern with a leading slash * fix: non-custom strategy error only happen when user dont use the appropriate api * fix: there is no way found route params is not an array, expect if user break internals * test: Constrainer.noteUsage * Cannot derive constraints without active strategies. * test: should derive multiple async constraints * test: Major version must be a numeric value * test: SemVerStore.maxMajor should increase automatically * test: SemVerStore.maxPatches should increase automatically * refactor: httpMethods module should be a source of truth * refactor: make consistent use of fmw.on * fix: istanbul should ignore the complete function * test: remove 90 min limit for code coverage * fix: when no args is passed, undefined is default value * fix: add new line at the end of .taprc * fix: readd removed comment indicating static route
1 parent 9731ad7 commit e117960

9 files changed

+274
-55
lines changed

.taprc

-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
11
ts: false
22
jsx: false
33
flow: false
4-
branches: 90
5-
functions: 90
6-
lines: 90
7-
statements: 90

index.js

+25-35
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,6 @@ Router.prototype.findRoute = function findNode (method, path, constraints = {})
344344
const isRegexParam = charCode === 40
345345
const isStaticPart = charCode === 45 || charCode === 46
346346
const isEndOfNode = charCode === 47 || j === pattern.length
347-
348347
if (isRegexParam || isStaticPart || isEndOfNode) {
349348
const paramName = pattern.slice(lastParamStartIndex, j)
350349
params.push(paramName)
@@ -407,9 +406,7 @@ Router.prototype.findRoute = function findNode (method, path, constraints = {})
407406
// add the wildcard parameter
408407
params.push('*')
409408
currentNode = currentNode.getWildcardChild()
410-
if (currentNode === null) {
411-
return null
412-
}
409+
413410
parentNodePathIndex = i + 1
414411

415412
if (i !== pattern.length - 1) {
@@ -422,10 +419,6 @@ Router.prototype.findRoute = function findNode (method, path, constraints = {})
422419
pattern = pattern.toLowerCase()
423420
}
424421

425-
if (pattern === '*') {
426-
pattern = '/*'
427-
}
428-
429422
for (const existRoute of this.routes) {
430423
const routeConstraints = existRoute.opts.constraints || {}
431424
if (
@@ -436,7 +429,7 @@ Router.prototype.findRoute = function findNode (method, path, constraints = {})
436429
return {
437430
handler: existRoute.handler,
438431
store: existRoute.store,
439-
params: existRoute.params || []
432+
params: existRoute.params
440433
}
441434
}
442435
}
@@ -642,37 +635,36 @@ Router.prototype.find = function find (method, path, derivedConstraints) {
642635
continue
643636
}
644637

645-
if (currentNode.kind === NODE_TYPES.PARAMETRIC) {
646-
let paramEndIndex = originPath.indexOf('/', pathIndex)
647-
if (paramEndIndex === -1) {
648-
paramEndIndex = pathLen
649-
}
638+
// parametric node
639+
let paramEndIndex = originPath.indexOf('/', pathIndex)
640+
if (paramEndIndex === -1) {
641+
paramEndIndex = pathLen
642+
}
650643

651-
let param = originPath.slice(pathIndex, paramEndIndex)
652-
if (shouldDecodeParam) {
653-
param = safeDecodeURIComponent(param)
654-
}
644+
let param = originPath.slice(pathIndex, paramEndIndex)
645+
if (shouldDecodeParam) {
646+
param = safeDecodeURIComponent(param)
647+
}
655648

656-
if (currentNode.isRegex) {
657-
const matchedParameters = currentNode.regex.exec(param)
658-
if (matchedParameters === null) continue
649+
if (currentNode.isRegex) {
650+
const matchedParameters = currentNode.regex.exec(param)
651+
if (matchedParameters === null) continue
659652

660-
for (let i = 1; i < matchedParameters.length; i++) {
661-
const matchedParam = matchedParameters[i]
662-
if (matchedParam.length > maxParamLength) {
663-
return null
664-
}
665-
params.push(matchedParam)
666-
}
667-
} else {
668-
if (param.length > maxParamLength) {
653+
for (let i = 1; i < matchedParameters.length; i++) {
654+
const matchedParam = matchedParameters[i]
655+
if (matchedParam.length > maxParamLength) {
669656
return null
670657
}
671-
params.push(param)
658+
params.push(matchedParam)
672659
}
673-
674-
pathIndex = paramEndIndex
660+
} else {
661+
if (param.length > maxParamLength) {
662+
return null
663+
}
664+
params.push(param)
675665
}
666+
667+
pathIndex = paramEndIndex
676668
}
677669
}
678670

@@ -742,8 +734,6 @@ for (const i in httpMethods) {
742734
const m = httpMethods[i]
743735
const methodName = m.toLowerCase()
744736

745-
if (Router.prototype[methodName]) throw new Error('Method already exists: ' + methodName)
746-
747737
Router.prototype[methodName] = function (path, handler, store) {
748738
return this.on(m, path, handler, store)
749739
}

lib/constrainer.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,8 @@ class Constrainer {
153153
if (!strategy.isCustom) {
154154
if (key === 'version') {
155155
lines.push(' version: req.headers[\'accept-version\'],')
156-
} else if (key === 'host') {
157-
lines.push(' host: req.headers.host || req.headers[\':authority\'],')
158156
} else {
159-
throw new Error('unknown non-custom strategy for compiling constraint derivation function')
157+
lines.push(' host: req.headers.host || req.headers[\':authority\'],')
160158
}
161159
} else {
162160
lines.push(` ${strategy.name}: this.strategies.${key}.deriveConstraint(req, ctx),`)

lib/node.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,7 @@ class StaticNode extends ParentNode {
129129
}
130130

131131
getWildcardChild () {
132-
if (this.wildcardChild) {
133-
return this.wildcardChild
134-
}
135-
return null
132+
return this.wildcardChild
136133
}
137134

138135
createWildcardChild () {

lib/strategies/accept-version.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ SemVerStore.prototype.set = function (version, store) {
2020
}
2121
let [major, minor, patch] = version.split('.')
2222

23-
major = Number(major) || 0
23+
if (isNaN(major)) {
24+
throw new TypeError('Major version must be a numeric value')
25+
}
26+
27+
major = Number(major)
2428
minor = Number(minor) || 0
2529
patch = Number(patch) || 0
2630

@@ -38,7 +42,7 @@ SemVerStore.prototype.set = function (version, store) {
3842
this.store[`${major}.x.x`] = store
3943
}
4044

41-
if (patch >= (this.store[`${major}.${minor}`] || 0)) {
45+
if (patch >= (this.maxPatches[`${major}.${minor}`] || 0)) {
4246
this.maxPatches[`${major}.${minor}`] = patch
4347
this.store[`${major}.${minor}.x`] = store
4448
}

lib/strategies/http-method.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ module.exports = {
99
set: (type, store) => { handlers[type] = store }
1010
}
1111
},
12-
deriveConstraint: (req) => {
13-
/* istanbul ignore next */
14-
return req.method
15-
},
12+
deriveConstraint: /* istanbul ignore next */ (req) => req.method,
1613
mustMatchWhenDerived: true
1714
}

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"chalk": "^4.1.2",
4141
"inquirer": "^8.2.4",
4242
"pre-commit": "^1.2.2",
43+
"proxyquire": "^2.1.3",
4344
"rfdc": "^1.3.0",
4445
"simple-git": "^3.7.1",
4546
"standard": "^14.3.4",

test/constraint.custom.async.test.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const t = require('tap')
44
const test = t.test
55
const FindMyWay = require('..')
6+
const rfdc = require('rfdc')({ proto: true })
67

78
const customHeaderConstraint = {
89
name: 'requestedBy',
@@ -23,11 +24,14 @@ const customHeaderConstraint = {
2324
}
2425
}
2526

26-
test('should derive async constraint', t => {
27+
test('should derive multiple async constraints', t => {
2728
t.plan(2)
2829

29-
const router = FindMyWay({ constraints: { requestedBy: customHeaderConstraint } })
30-
router.on('GET', '/', { constraints: { requestedBy: 'node' } }, () => 'asyncHandler')
30+
const customHeaderConstraint2 = rfdc(customHeaderConstraint)
31+
customHeaderConstraint2.name = 'requestedBy2'
32+
33+
const router = FindMyWay({ constraints: { requestedBy: customHeaderConstraint, requestedBy2: customHeaderConstraint2 } })
34+
router.on('GET', '/', { constraints: { requestedBy: 'node', requestedBy2: 'node' } }, () => 'asyncHandler')
3135

3236
router.lookup(
3337
{

0 commit comments

Comments
 (0)