@pbvision/fastify-firestore-service 0.0.17 → 0.0.18
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/README.md +0 -5
- package/package.json +5 -4
- package/src/fetch-wrapper.js +9 -7
- package/test/base-test.js +38 -12
package/README.md
CHANGED
|
@@ -14,7 +14,6 @@ provides a way to define APIs, including managing data.
|
|
|
14
14
|
- [Components](#components)
|
|
15
15
|
- [Customizing Component Registration](#customizing-component-registration)
|
|
16
16
|
- [Unit testing](#unit-testing)
|
|
17
|
-
- [Setup](#setup)
|
|
18
17
|
- [Generating SDKs](#generating-sdks)
|
|
19
18
|
- [Swagger UI](#swagger-ui)
|
|
20
19
|
- [OpenAPI SDKs](#openapi-sdks)
|
|
@@ -175,10 +174,6 @@ workflow with custom components. For example, to add a new type of component
|
|
|
175
174
|
`makeService({ components: { ExampleComponent } })`
|
|
176
175
|
|
|
177
176
|
# Unit testing
|
|
178
|
-
## Setup
|
|
179
|
-
Apps store data in Firestore. You must start the Firestore emulator before
|
|
180
|
-
running tests. You can run `yarn start-local-db` to start the local emulator.
|
|
181
|
-
|
|
182
177
|
# Generating SDKs
|
|
183
178
|
## Swagger UI
|
|
184
179
|
This library generates an interactive Swagger UI for all APIs at /[service]/docs.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pbvision/fastify-firestore-service",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "Web Framework using Fastify and Firestore ORM",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build-doc": "./docs/build.sh",
|
|
13
13
|
"debug": "./node_modules/nodemon/bin/nodemon.js --no-lazy --legacy-watch --watch ./src --watch ./examples --watch ./test --inspect=9229 ./node_modules/jest/bin/jest.js --coverage --config=./jest.config.json --runInBand",
|
|
14
|
-
"test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --config=./jest.config.json --coverage",
|
|
15
14
|
"setup": "yarn install --frozen-lockfile && pip install -r requirements.txt",
|
|
16
|
-
"start-local-db": "./node_modules/@pbvision/firestore-orm/scripts/start-local-db.sh"
|
|
15
|
+
"start-local-db": "./node_modules/@pbvision/firestore-orm/scripts/start-local-db.sh",
|
|
16
|
+
"test": "yarn -s start-local-db && yarn -s test-without-starting-db",
|
|
17
|
+
"test-without-starting-db": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --config=./jest.config.json --coverage"
|
|
17
18
|
},
|
|
18
19
|
"contributors": [
|
|
19
20
|
"David Underhill",
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
"@fastify/static": "^6.12",
|
|
42
43
|
"@fastify/swagger": "^8.1.0",
|
|
43
44
|
"@fastify/swagger-ui": "^2.0.1",
|
|
44
|
-
"@pbvision/firestore-orm": "^0.0.
|
|
45
|
+
"@pbvision/firestore-orm": "^0.0.7",
|
|
45
46
|
"@pbvision/schema": "^0.2.15",
|
|
46
47
|
"@sentry/node": "^7.91.0",
|
|
47
48
|
"fastify": "^4.10.0",
|
package/src/fetch-wrapper.js
CHANGED
|
@@ -3,23 +3,24 @@ import zlib from 'node:zlib'
|
|
|
3
3
|
|
|
4
4
|
import realFetch from 'node-fetch'
|
|
5
5
|
|
|
6
|
-
async function fetchWrapper (
|
|
7
|
-
const { compress = true, method = 'POST', url, qsParams, json } =
|
|
8
|
-
let { body, headers } =
|
|
6
|
+
async function fetchWrapper (request, mockedFetch) {
|
|
7
|
+
const { compress = true, method = 'POST', url, qsParams, json } = request
|
|
8
|
+
let { body, headers } = request
|
|
9
9
|
headers = { ...headers } // copy the headers before we change them
|
|
10
10
|
|
|
11
11
|
// compress the body using brotli
|
|
12
12
|
if (json) {
|
|
13
13
|
headers['content-type'] = 'application/json'
|
|
14
|
-
body = JSON.stringify(
|
|
14
|
+
body = JSON.stringify(request.json)
|
|
15
15
|
}
|
|
16
16
|
if (body && compress) {
|
|
17
17
|
body = zlib.brotliCompressSync(body)
|
|
18
18
|
headers['content-encoding'] = 'br'
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const fetch = (mockedFetch === false)
|
|
22
|
+
? realFetch
|
|
23
|
+
: (mockedFetch ?? fetchWrapper.__mock ?? realFetch)
|
|
23
24
|
|
|
24
25
|
// compute the full URL including search params
|
|
25
26
|
let fullURL = url
|
|
@@ -29,7 +30,8 @@ async function fetchWrapper (options, mockedFetch) {
|
|
|
29
30
|
fullURL += `?${qsStr}`
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
const options = { body, headers, method, compress: false }
|
|
34
|
+
return fetch(fullURL, options)
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export default fetchWrapper
|
package/test/base-test.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import querystring from 'node:querystring'
|
|
1
2
|
import zlib from 'node:zlib'
|
|
2
3
|
|
|
3
4
|
import { jest } from '@jest/globals'
|
|
@@ -27,6 +28,10 @@ class BaseAppTest extends BaseTest {
|
|
|
27
28
|
beforeEach () {
|
|
28
29
|
this.fetchMock = fetchWrapper.__mock
|
|
29
30
|
fetchWrapper.__mock.mockClear()
|
|
31
|
+
|
|
32
|
+
// default response is a weird error to help make it obvious the unit test
|
|
33
|
+
// author forgot to provide a custom mock value
|
|
34
|
+
this.fetchMock.mockResp('custom mock value not set', 555)
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
async beforeAll () {
|
|
@@ -73,15 +78,15 @@ function makeHeadersObj (headers) {
|
|
|
73
78
|
// so you can pass the output of app.post(), etc. as the promise here as is
|
|
74
79
|
function makeNodeFetchMockValueFromPromise (promise) {
|
|
75
80
|
const mockValue = new Promise(resolve => {
|
|
76
|
-
promise.then(
|
|
77
|
-
let body =
|
|
81
|
+
promise.then(httpResponse => {
|
|
82
|
+
let body = httpResponse.text || httpResponse.body || ''
|
|
78
83
|
const headers = {}
|
|
79
84
|
if (typeof body !== 'string') {
|
|
80
85
|
body = JSON.stringify(body)
|
|
81
86
|
headers['content-type'] = 'application/json'
|
|
82
87
|
}
|
|
83
88
|
resolve({
|
|
84
|
-
status:
|
|
89
|
+
status: httpResponse.status || 200,
|
|
85
90
|
headers: makeHeadersObj(headers),
|
|
86
91
|
text: async () => body
|
|
87
92
|
})
|
|
@@ -120,9 +125,7 @@ function makeNodeFetchMockValue (body, status, callback) {
|
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
function mockNodeFetch () {
|
|
123
|
-
const nodeFetchMock = jest.fn().mockImplementation(
|
|
124
|
-
expect(body).toEqual(zlib.brotliCompressSync('321'))
|
|
125
|
-
})
|
|
128
|
+
const nodeFetchMock = jest.fn().mockImplementation()
|
|
126
129
|
|
|
127
130
|
nodeFetchMock.mockResp = (body = '', statusCode = 200, callback) => {
|
|
128
131
|
nodeFetchMock.mockReturnValue(makeNodeFetchMockValue(body, statusCode, callback))
|
|
@@ -136,12 +139,34 @@ function mockNodeFetch () {
|
|
|
136
139
|
* provides a mock response then an error will be thrown
|
|
137
140
|
*/
|
|
138
141
|
nodeFetchMock.mockRespWithCallback = (...callbacks) => {
|
|
139
|
-
nodeFetchMock.mockImplementation(
|
|
142
|
+
nodeFetchMock.mockImplementation((fullURL, options) => {
|
|
143
|
+
// construct the fetchWrapper's request parameter from the fullURL and
|
|
144
|
+
// options passed as parameters to node-fetch
|
|
145
|
+
const [baseUrl, qsParams] = fullURL.split('?', 2)
|
|
146
|
+
const request = {
|
|
147
|
+
compress: options.headers['content-encoding'] === 'br',
|
|
148
|
+
method: options.method,
|
|
149
|
+
url: baseUrl,
|
|
150
|
+
qsParams: querystring.parse(qsParams),
|
|
151
|
+
headers: options.headers
|
|
152
|
+
}
|
|
153
|
+
delete request.headers['content-encoding']
|
|
154
|
+
const body = options.body
|
|
155
|
+
? (request.compress
|
|
156
|
+
? zlib.brotliDecompressSync(options.body)
|
|
157
|
+
: options.body)
|
|
158
|
+
: options.body
|
|
159
|
+
if (options.headers['content-type'] === 'application/json') {
|
|
160
|
+
delete options.headers['content-type']
|
|
161
|
+
request.json = JSON.parse(body)
|
|
162
|
+
} else {
|
|
163
|
+
request.body = body // may be undefined
|
|
164
|
+
}
|
|
165
|
+
|
|
140
166
|
for (const callback of callbacks) {
|
|
141
167
|
const desiredHTTPResponse = callback(request)
|
|
142
168
|
if (desiredHTTPResponse === true) {
|
|
143
|
-
|
|
144
|
-
return unmockedFetch(request)
|
|
169
|
+
return fetchWrapper(request, false)
|
|
145
170
|
}
|
|
146
171
|
if (desiredHTTPResponse) {
|
|
147
172
|
if (desiredHTTPResponse.then) {
|
|
@@ -162,10 +187,11 @@ function mockNodeFetch () {
|
|
|
162
187
|
let idx = 0
|
|
163
188
|
function setupNextResponse () {
|
|
164
189
|
if (idx < responses.length) {
|
|
165
|
-
|
|
166
|
-
|
|
190
|
+
const [body, code] = responses[idx]
|
|
191
|
+
nodeFetchMock.mockResp(body ?? '', code ?? 200, setupNextResponse)
|
|
192
|
+
} else {
|
|
167
193
|
// exactly equal means we just got our last callback (okay)
|
|
168
|
-
|
|
194
|
+
nodeFetchMock.mockResp('ran out of mocked responses', 556)
|
|
169
195
|
}
|
|
170
196
|
idx += 1
|
|
171
197
|
}
|