Skip to content

Commit a5cfd47

Browse files
authored
Execute tests using TAP, allow jest tests to fail (#50)
1 parent fb99bbb commit a5cfd47

9 files changed

+256
-8
lines changed

.github/workflows/ci-jest.yml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CI-jest
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
paths-ignore:
8+
- 'docs/**'
9+
- '*.md'
10+
pull_request:
11+
branches:
12+
- master
13+
paths-ignore:
14+
- 'docs/**'
15+
- '*.md'
16+
17+
jobs:
18+
test:
19+
runs-on: ${{ matrix.os }}
20+
21+
strategy:
22+
matrix:
23+
node-version: [10, 12, 14, 15, 16]
24+
os: [ubuntu-latest]
25+
continue-on-error: true
26+
27+
steps:
28+
- uses: actions/[email protected]
29+
30+
- name: Use Node.js
31+
uses: actions/[email protected]
32+
with:
33+
node-version: ${{ matrix.node-version }}
34+
35+
- name: Install Dependencies
36+
run: |
37+
npm install --ignore-scripts
38+
39+
- name: Run Tests
40+
run: |
41+
npm run test:jest

.github/workflows/ci.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ name: CI
22

33
on:
44
push:
5+
branches:
6+
- master
57
paths-ignore:
68
- 'docs/**'
79
- '*.md'
810
pull_request:
11+
branches:
12+
- master
913
paths-ignore:
1014
- 'docs/**'
1115
- '*.md'
@@ -31,9 +35,9 @@ jobs:
3135
run: |
3236
npm install --ignore-scripts
3337
34-
- name: Run Tests
38+
- name: Run Tests With Tap
3539
run: |
36-
npm test
40+
npm run test:tap
3741
3842
automerge:
3943
needs: test

.github/workflows/linting.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717

1818
strategy:
1919
matrix:
20-
node-version: [15]
20+
node-version: [16]
2121

2222
steps:
2323
- name: Checkout Repository

.husky/pre-commit

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/bin/sh
22
. "$(dirname $0)/_/husky.sh"
33

4-
npm run test
4+
npm run test:tap
55
npm run lint:everything

lib/requestContextPlugin.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use strict'
2+
13
const fp = require('fastify-plugin')
24
const { als } = require('asynchronous-local-storage')
35
const { AsyncResource } = require('async_hooks')

package.json

+6-4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
"main": "index.js",
1313
"types": "index.d.ts",
1414
"scripts": {
15-
"test": "jest --config=jest.config.json",
16-
"test:coverage": "jest --config=jest.config.json --coverage",
15+
"test:coverage": "tap -J test-tap/*.test.js --cov --coverage-report=lcovonly",
16+
"test:jest": "jest --config=jest.config.json",
17+
"test:tap": "tap -J test-tap/*.test.js",
1718
"test:typescript": "tsd",
18-
"lint": "eslint --format codeframe \"lib/**/*.js\" \"test/**/*.js\" index.js",
19+
"lint": "eslint --format codeframe \"lib/**/*.js\" \"test/**/*.js\" \"test-tap/**/*.js\" index.js",
1920
"lint:everything": "npm run lint && npm run test:typescript",
20-
"prettier": "prettier --write \"{lib,test}/**/*.js\" index.js index.d.ts",
21+
"prettier": "prettier --write \"{lib,test,test-tap}/**/*.js\" index.js index.d.ts",
2122
"postinstall": "husky install",
2223
"prepublishOnly": "pinst --disable",
2324
"postpublish": "pinst --enable"
@@ -40,6 +41,7 @@
4041
"pinst": "^2.1.1",
4142
"prettier": "^2.2.1",
4243
"superagent": "^6.1.0",
44+
"tap": "^15.0.9",
4345
"tsd": "^0.15.0",
4446
"typescript": "4.2.4"
4547
},
+195
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
'use strict'
2+
3+
const request = require('superagent')
4+
const {
5+
initAppPostWithPrevalidation,
6+
initAppPostWithAllPlugins,
7+
} = require('../test/internal/appInitializer')
8+
const { TestService } = require('../test/internal/testService')
9+
const t = require('tap')
10+
const test = t.test
11+
12+
let app
13+
t.afterEach(() => {
14+
return app.close()
15+
})
16+
17+
test('correctly preserves values set in prevalidation phase within single POST request', (t) => {
18+
t.plan(2)
19+
20+
let testService
21+
let responseCounter = 0
22+
return new Promise((resolveResponsePromise) => {
23+
const promiseRequest2 = new Promise((resolveRequest2Promise) => {
24+
const promiseRequest1 = new Promise((resolveRequest1Promise) => {
25+
const route = (req) => {
26+
const requestId = req.requestContext.get('testKey')
27+
28+
function prepareReply() {
29+
return testService.processRequest(requestId.replace('testValue', '')).then(() => {
30+
const storedValue = req.requestContext.get('testKey')
31+
return Promise.resolve({ storedValue })
32+
})
33+
}
34+
35+
// We don't want to read values until both requests wrote their values to see if there is a racing condition
36+
if (requestId === 'testValue1') {
37+
resolveRequest1Promise()
38+
return promiseRequest2.then(prepareReply)
39+
}
40+
41+
if (requestId === 'testValue2') {
42+
resolveRequest2Promise()
43+
return promiseRequest1.then(prepareReply)
44+
}
45+
46+
throw new Error(`Unexpected requestId: ${requestId}`)
47+
}
48+
49+
app = initAppPostWithPrevalidation(route)
50+
app.listen(0).then(() => {
51+
testService = new TestService(app)
52+
const { address, port } = app.server.address()
53+
const url = `${address}:${port}`
54+
const response1Promise = request('POST', url)
55+
.send({ requestId: 1 })
56+
.then((response) => {
57+
t.equal(response.body.storedValue, 'testValue1')
58+
responseCounter++
59+
if (responseCounter === 2) {
60+
resolveResponsePromise()
61+
}
62+
})
63+
64+
const response2Promise = request('POST', url)
65+
.send({ requestId: 2 })
66+
.then((response) => {
67+
t.equal(response.body.storedValue, 'testValue2')
68+
responseCounter++
69+
if (responseCounter === 2) {
70+
resolveResponsePromise()
71+
}
72+
})
73+
74+
return Promise.all([response1Promise, response2Promise])
75+
})
76+
})
77+
78+
return promiseRequest1
79+
})
80+
81+
return promiseRequest2
82+
})
83+
})
84+
85+
test('correctly preserves values set in multiple phases within single POST request', (t) => {
86+
t.plan(10)
87+
88+
let testService
89+
let responseCounter = 0
90+
return new Promise((resolveResponsePromise) => {
91+
const promiseRequest2 = new Promise((resolveRequest2Promise) => {
92+
const promiseRequest1 = new Promise((resolveRequest1Promise) => {
93+
const route = (req) => {
94+
const onRequestValue = req.requestContext.get('onRequest')
95+
const preParsingValue = req.requestContext.get('preParsing')
96+
const preValidationValue = req.requestContext.get('preValidation')
97+
const preHandlerValue = req.requestContext.get('preHandler')
98+
99+
t.equal(onRequestValue, undefined)
100+
t.equal(preParsingValue, undefined)
101+
t.type(preValidationValue, 'number')
102+
t.type(preHandlerValue, 'number')
103+
104+
const requestId = `testValue${preHandlerValue}`
105+
106+
function prepareReply() {
107+
return testService.processRequest(requestId.replace('testValue', '')).then(() => {
108+
const storedValue = req.requestContext.get('preValidation')
109+
return Promise.resolve({ storedValue: `testValue${storedValue}` })
110+
})
111+
}
112+
113+
// We don't want to read values until both requests wrote their values to see if there is a racing condition
114+
if (requestId === 'testValue1') {
115+
resolveRequest1Promise()
116+
return promiseRequest2.then(prepareReply)
117+
}
118+
119+
if (requestId === 'testValue2') {
120+
resolveRequest2Promise()
121+
return promiseRequest1.then(prepareReply)
122+
}
123+
124+
throw new Error(`Unexpected requestId: ${requestId}`)
125+
}
126+
127+
app = initAppPostWithAllPlugins(route, 'preValidation')
128+
129+
app.listen(0).then(() => {
130+
testService = new TestService(app)
131+
const { address, port } = app.server.address()
132+
const url = `${address}:${port}`
133+
const response1Promise = request('POST', url)
134+
.send({ requestId: 1 })
135+
.then((response) => {
136+
t.equal(response.body.storedValue, 'testValue1')
137+
responseCounter++
138+
if (responseCounter === 2) {
139+
resolveResponsePromise()
140+
}
141+
})
142+
143+
const response2Promise = request('POST', url)
144+
.send({ requestId: 2 })
145+
.then((response) => {
146+
t.equal(response.body.storedValue, 'testValue2')
147+
responseCounter++
148+
if (responseCounter === 2) {
149+
resolveResponsePromise()
150+
}
151+
})
152+
153+
return Promise.all([response1Promise, response2Promise])
154+
})
155+
})
156+
157+
return promiseRequest1
158+
})
159+
160+
return promiseRequest2
161+
})
162+
})
163+
164+
test('correctly preserves values set in multiple phases within single POST request', (t) => {
165+
t.plan(7)
166+
167+
const route = (req) => {
168+
const onRequestValue = req.requestContext.get('onRequest')
169+
const preParsingValue = req.requestContext.get('preParsing')
170+
const preValidationValue = req.requestContext.get('preValidation')
171+
const preHandlerValue = req.requestContext.get('preHandler')
172+
173+
t.equal(onRequestValue, 'dummy')
174+
t.equal(preParsingValue, 'dummy')
175+
t.type(preValidationValue, 'number')
176+
t.type(preHandlerValue, 'number')
177+
178+
const requestId = `testValue${preHandlerValue}`
179+
return Promise.resolve({ storedValue: requestId })
180+
}
181+
182+
app = initAppPostWithAllPlugins(route)
183+
184+
return app.listen(0).then(() => {
185+
const { address, port } = app.server.address()
186+
const url = `${address}:${port}`
187+
return request('POST', url)
188+
.send({ requestId: 1 })
189+
.then((response) => {
190+
t.equal(response.body.storedValue, 'testValue1')
191+
t.equal(response.body.preSerialization1, 'dummy')
192+
t.equal(response.body.preSerialization2, 1)
193+
})
194+
})
195+
})

test/requestContextPlugin.e2e.spec.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use strict'
2+
13
const request = require('superagent')
24
const {
35
initAppPostWithPrevalidation,

test/requestContextPlugin.spec.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use strict'
2+
13
const {
24
initAppPost,
35
initAppPostWithPrevalidation,

0 commit comments

Comments
 (0)