@dereekb/firebase-server 13.0.0 → 13.0.2
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/index.cjs.default.js +1 -0
- package/index.cjs.js +1923 -2001
- package/index.cjs.mjs +2 -0
- package/index.esm.js +1924 -2000
- package/mailgun/index.cjs.default.js +1 -0
- package/mailgun/index.cjs.js +28 -35
- package/mailgun/index.cjs.mjs +2 -0
- package/mailgun/index.esm.js +28 -35
- package/mailgun/package.json +17 -22
- package/model/index.cjs.default.js +1 -0
- package/model/index.cjs.js +4042 -4573
- package/model/index.cjs.mjs +2 -0
- package/model/index.esm.js +4042 -4573
- package/model/package.json +23 -27
- package/package.json +42 -61
- package/src/lib/function/error.d.ts +0 -8
- package/test/index.cjs.default.js +1 -0
- package/test/index.cjs.js +867 -933
- package/test/index.cjs.mjs +2 -0
- package/test/index.esm.js +867 -933
- package/test/package.json +22 -26
- package/zoho/index.cjs.default.js +1 -0
- package/zoho/index.cjs.js +82 -85
- package/zoho/index.cjs.mjs +2 -0
- package/zoho/index.esm.js +82 -85
- package/zoho/package.json +17 -21
package/test/index.cjs.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
require('core-js/modules/es.json.parse.js');
|
|
4
|
-
require('core-js/modules/es.json.stringify.js');
|
|
5
3
|
var util = require('@dereekb/util');
|
|
6
4
|
var test = require('@dereekb/util/test');
|
|
7
5
|
var jsonwebtoken = require('jsonwebtoken');
|
|
@@ -12,143 +10,133 @@ var test$1 = require('@dereekb/firebase/test');
|
|
|
12
10
|
var firebaseServer = require('@dereekb/firebase-server');
|
|
13
11
|
var firestore = require('@google-cloud/firestore');
|
|
14
12
|
var storage = require('@google-cloud/storage');
|
|
15
|
-
require('core-js/modules/es.iterator.constructor.js');
|
|
16
|
-
require('core-js/modules/es.iterator.for-each.js');
|
|
17
13
|
var testing = require('@nestjs/testing');
|
|
18
14
|
var nestjs = require('@dereekb/nestjs');
|
|
19
15
|
var https = require('firebase-functions/v1/https');
|
|
20
16
|
var makeError = require('make-error');
|
|
21
17
|
|
|
22
18
|
class AuthorizedUserTestContextFixture extends test.AbstractChildTestContextFixture {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
19
|
+
// MARK: AuthorizedUserTestContext (Forwarded)
|
|
20
|
+
get uid() {
|
|
21
|
+
return this.instance.uid;
|
|
22
|
+
}
|
|
23
|
+
loadUserRecord() {
|
|
24
|
+
return this.instance.loadUserRecord();
|
|
25
|
+
}
|
|
26
|
+
loadUserEmailAndPhone() {
|
|
27
|
+
return this.instance.loadUserEmailAndPhone();
|
|
28
|
+
}
|
|
29
|
+
loadIdToken() {
|
|
30
|
+
return this.instance.loadIdToken();
|
|
31
|
+
}
|
|
32
|
+
loadDecodedIdToken() {
|
|
33
|
+
return this.instance.loadDecodedIdToken();
|
|
34
|
+
}
|
|
35
|
+
makeContextOptions() {
|
|
36
|
+
return this.instance.makeContextOptions();
|
|
37
|
+
}
|
|
38
|
+
callWrappedFunction(fn, params, skipJsonConversion) {
|
|
39
|
+
return this.instance.callWrappedFunction(fn, params, skipJsonConversion);
|
|
40
|
+
}
|
|
41
|
+
callCloudFunction(fn, params, skipJsonConversion = false) {
|
|
42
|
+
return this.instance.callCloudFunction(fn, params, skipJsonConversion);
|
|
43
|
+
}
|
|
48
44
|
}
|
|
49
45
|
function convertParamsToParsedJsonObjectAndBack(object) {
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
const paramsAsJson = JSON.parse(JSON.stringify(object));
|
|
47
|
+
return paramsAsJson;
|
|
52
48
|
}
|
|
53
49
|
class AuthorizedUserTestContextInstance {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const parsedParams = params == null || skipJsonConversion ? params : convertParamsToParsedJsonObjectAndBack(params);
|
|
139
|
-
return this.makeContextOptions().then(options => fn(parsedParams, contextOptions ? {
|
|
140
|
-
...contextOptions,
|
|
141
|
-
...options
|
|
142
|
-
} : options));
|
|
143
|
-
}
|
|
50
|
+
uid;
|
|
51
|
+
testContext;
|
|
52
|
+
constructor(uid, testContext) {
|
|
53
|
+
this.uid = uid;
|
|
54
|
+
this.testContext = testContext;
|
|
55
|
+
}
|
|
56
|
+
loadUserRecord() {
|
|
57
|
+
return this.testContext.auth.getUser(this.uid);
|
|
58
|
+
}
|
|
59
|
+
async loadUserEmailAndPhone() {
|
|
60
|
+
const record = await this.loadUserRecord();
|
|
61
|
+
return {
|
|
62
|
+
email: record.email,
|
|
63
|
+
phone: record.phoneNumber
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
loadIdToken() {
|
|
67
|
+
return this.loadUserRecord().then((record) => createEncodedTestFirestoreTokenForUserRecord(this.testContext.auth, record));
|
|
68
|
+
}
|
|
69
|
+
loadDecodedIdToken() {
|
|
70
|
+
return this.loadIdToken().then(decodeEncodedCreateCustomTokenResult);
|
|
71
|
+
}
|
|
72
|
+
makeContextOptions() {
|
|
73
|
+
return this.loadUserRecord().then((record) => createTestFunctionContextOptions(this.testContext.auth, record));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Calls a wrapped function with the input params and the context from makeContextOptions().
|
|
77
|
+
*
|
|
78
|
+
* @param fn
|
|
79
|
+
* @param params
|
|
80
|
+
* @param skipJsonConversion
|
|
81
|
+
*/
|
|
82
|
+
callWrappedFunction(fn, params, skipJsonConversion) {
|
|
83
|
+
// Parse to JSON then back to simulate sending JSON to the server, and the server parsing it as a POJO.
|
|
84
|
+
const parsedParams = params == null || skipJsonConversion ? params : convertParamsToParsedJsonObjectAndBack(params);
|
|
85
|
+
return this.makeContextOptions().then((options) => fn(parsedParams, options));
|
|
86
|
+
}
|
|
87
|
+
callCloudFunction(fn, params, skipJsonConversion = false) {
|
|
88
|
+
if (params != null && params.scheduleTime) {
|
|
89
|
+
// Workaround for https://github.com/firebase/firebase-functions-test/issues/210
|
|
90
|
+
const scheduleTime = params.scheduleTime;
|
|
91
|
+
delete params.scheduleTime;
|
|
92
|
+
params.timestamp = scheduleTime;
|
|
93
|
+
}
|
|
94
|
+
return this.callWrappedFunction(fn, params, skipJsonConversion);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Calls a wrapped gen 2 auth blocking function with the input params and context options from makeContextOptions().
|
|
98
|
+
*
|
|
99
|
+
* @param fn
|
|
100
|
+
* @param userRecord
|
|
101
|
+
* @param eventType
|
|
102
|
+
* @param eventOverride
|
|
103
|
+
* @param skipJsonConversion
|
|
104
|
+
* @returns
|
|
105
|
+
*/
|
|
106
|
+
callAuthBlockingFunction(fn, userRecord, eventType, eventOverride, skipJsonConversion = false) {
|
|
107
|
+
const timestamp = new Date().toISOString();
|
|
108
|
+
const event = {
|
|
109
|
+
ipAddress: '127.0.0.1',
|
|
110
|
+
userAgent: 'testing',
|
|
111
|
+
eventId: '0',
|
|
112
|
+
params: {},
|
|
113
|
+
resource: { service: 'dbx-test', name: 'fake-resource' },
|
|
114
|
+
timestamp,
|
|
115
|
+
...eventOverride,
|
|
116
|
+
data: userRecord,
|
|
117
|
+
eventType
|
|
118
|
+
};
|
|
119
|
+
return this.callCloudFunction(fn, event, skipJsonConversion);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* @deprecated gen 1
|
|
123
|
+
*
|
|
124
|
+
* @param fn
|
|
125
|
+
* @param params
|
|
126
|
+
* @param contextOptions
|
|
127
|
+
* @param skipJsonConversion
|
|
128
|
+
* @returns
|
|
129
|
+
*/
|
|
130
|
+
callEventCloudFunction(fn, params, contextOptions, skipJsonConversion = false) {
|
|
131
|
+
const parsedParams = params == null || skipJsonConversion ? params : convertParamsToParsedJsonObjectAndBack(params);
|
|
132
|
+
return this.makeContextOptions().then((options) => fn(parsedParams, contextOptions ? { ...contextOptions, ...options } : options));
|
|
133
|
+
}
|
|
144
134
|
}
|
|
145
135
|
/**
|
|
146
136
|
* Convenience function for using authorizedUserContextFactory directly and passing buildTests.
|
|
147
137
|
*/
|
|
148
138
|
function authorizedUserContext(config, buildTests) {
|
|
149
|
-
|
|
150
|
-
f: config.f
|
|
151
|
-
}, buildTests);
|
|
139
|
+
authorizedUserContextFactory(config)({ f: config.f }, buildTests);
|
|
152
140
|
}
|
|
153
141
|
const AUTHORIZED_USER_RANDOM_EMAIL_FACTORY = util.randomEmailFactory();
|
|
154
142
|
const AUTHORIZED_USER_RANDOM_PHONE_NUMBER_FACTORY = util.randomPhoneNumberFactory();
|
|
@@ -156,86 +144,66 @@ const AUTHORIZED_USER_RANDOM_PHONE_NUMBER_FACTORY = util.randomPhoneNumberFactor
|
|
|
156
144
|
* Creates a new Jest Context that has a random user for authorization for use in firebase server tests.
|
|
157
145
|
*/
|
|
158
146
|
function authorizedUserContextFactory(config) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
displayName: 'Test Person',
|
|
211
|
-
...details,
|
|
212
|
-
email,
|
|
213
|
-
phoneNumber,
|
|
214
|
-
...inputUser
|
|
147
|
+
const { uid: uidGetter, makeInstance = (uid, testInstance) => new AuthorizedUserTestContextInstance(uid, testInstance), makeFixture = (f) => new AuthorizedUserTestContextFixture(f), makeUserDetails = () => ({}), initUser } = config;
|
|
148
|
+
const makeUid = uidGetter ? util.asGetter(uidGetter) : testUidFactory;
|
|
149
|
+
return (params, buildTests) => {
|
|
150
|
+
const { f, user: inputUserGetterOrValue, addContactInfo: inputAddContactInfoGetterOrValue, template: inputTemplateGetterOrValue } = params;
|
|
151
|
+
const inputAddContactInfoGetter = util.asGetter(inputAddContactInfoGetterOrValue);
|
|
152
|
+
const inputUserGetter = util.asGetter(inputUserGetterOrValue);
|
|
153
|
+
const templateGetter = util.asGetter(inputTemplateGetterOrValue);
|
|
154
|
+
return test.useTestContextFixture({
|
|
155
|
+
fixture: makeFixture(f),
|
|
156
|
+
buildTests,
|
|
157
|
+
initInstance: async () => {
|
|
158
|
+
const inputAddContactInfo = await inputAddContactInfoGetter();
|
|
159
|
+
const inputUser = await inputUserGetter();
|
|
160
|
+
const inputTemplate = await templateGetter();
|
|
161
|
+
const uid = inputUser?.uid || makeUid();
|
|
162
|
+
const { details, claims, addContactInfo: userDetailsAddContactInfo } = { ...makeUserDetails(uid, params), ...inputTemplate };
|
|
163
|
+
const { phoneNumber: detailsPhoneNumber, email: detailsEmail } = details ?? {}; // keep details if provided
|
|
164
|
+
const addContactInfo = inputAddContactInfo || userDetailsAddContactInfo;
|
|
165
|
+
const auth = f.instance.auth;
|
|
166
|
+
let email;
|
|
167
|
+
let phoneNumber;
|
|
168
|
+
if (addContactInfo) {
|
|
169
|
+
email = detailsEmail ?? AUTHORIZED_USER_RANDOM_EMAIL_FACTORY();
|
|
170
|
+
phoneNumber = detailsPhoneNumber ?? AUTHORIZED_USER_RANDOM_PHONE_NUMBER_FACTORY();
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
email = detailsEmail;
|
|
174
|
+
phoneNumber = detailsPhoneNumber ?? undefined;
|
|
175
|
+
}
|
|
176
|
+
const userRecord = await auth.createUser({
|
|
177
|
+
uid,
|
|
178
|
+
displayName: 'Test Person',
|
|
179
|
+
...details,
|
|
180
|
+
email,
|
|
181
|
+
phoneNumber,
|
|
182
|
+
...inputUser
|
|
183
|
+
});
|
|
184
|
+
if (claims) {
|
|
185
|
+
await auth.setCustomUserClaims(uid, claims);
|
|
186
|
+
}
|
|
187
|
+
const instance = await makeInstance(uid, f.instance, params, userRecord);
|
|
188
|
+
if (initUser) {
|
|
189
|
+
await initUser(instance, params);
|
|
190
|
+
}
|
|
191
|
+
return instance;
|
|
192
|
+
},
|
|
193
|
+
destroyInstance: async (instance) => {
|
|
194
|
+
const app = instance.testContext.app;
|
|
195
|
+
const uid = instance.uid;
|
|
196
|
+
await app.auth().deleteUser(uid);
|
|
197
|
+
}
|
|
215
198
|
});
|
|
216
|
-
|
|
217
|
-
await auth.setCustomUserClaims(uid, claims);
|
|
218
|
-
}
|
|
219
|
-
const instance = await makeInstance(uid, f.instance, params, userRecord);
|
|
220
|
-
if (initUser) {
|
|
221
|
-
await initUser(instance, params);
|
|
222
|
-
}
|
|
223
|
-
return instance;
|
|
224
|
-
},
|
|
225
|
-
destroyInstance: async instance => {
|
|
226
|
-
const app = instance.testContext.app;
|
|
227
|
-
const uid = instance.uid;
|
|
228
|
-
await app.auth().deleteUser(uid);
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
};
|
|
199
|
+
};
|
|
232
200
|
}
|
|
233
201
|
/**
|
|
234
202
|
* Incrementing number factory for generating test UID values.
|
|
235
203
|
*
|
|
236
204
|
* Has the format 'test-uid-<number>'
|
|
237
205
|
*/
|
|
238
|
-
const testUidFactory = util.mapGetter(util.incrementingNumberFactory(), i => `${new Date().getTime()}0${i}`);
|
|
206
|
+
const testUidFactory = util.mapGetter(util.incrementingNumberFactory(), (i) => `${new Date().getTime()}0${i}`);
|
|
239
207
|
/**
|
|
240
208
|
* Creates a CallableContextOptions with auth attached corresponding to the input UserRecord.
|
|
241
209
|
*
|
|
@@ -244,11 +212,11 @@ const testUidFactory = util.mapGetter(util.incrementingNumberFactory(), i => `${
|
|
|
244
212
|
* @returns
|
|
245
213
|
*/
|
|
246
214
|
async function createTestFunctionContextOptions(auth, userRecord) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
215
|
+
const authData = await createTestFunctionContextAuthData(auth, userRecord);
|
|
216
|
+
const contextOptions = {
|
|
217
|
+
auth: authData
|
|
218
|
+
};
|
|
219
|
+
return contextOptions;
|
|
252
220
|
}
|
|
253
221
|
/**
|
|
254
222
|
* Creates AuthData from the input auth and user record.
|
|
@@ -258,13 +226,13 @@ async function createTestFunctionContextOptions(auth, userRecord) {
|
|
|
258
226
|
* @returns
|
|
259
227
|
*/
|
|
260
228
|
async function createTestFunctionContextAuthData(auth, userRecord) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
229
|
+
const token = await createTestFirestoreTokenForUserRecord(auth, userRecord);
|
|
230
|
+
const authData = {
|
|
231
|
+
uid: token.uid,
|
|
232
|
+
token,
|
|
233
|
+
rawToken: ''
|
|
234
|
+
};
|
|
235
|
+
return authData;
|
|
268
236
|
}
|
|
269
237
|
/**
|
|
270
238
|
* Creates and decodes a firestore token used for testing.
|
|
@@ -274,7 +242,7 @@ async function createTestFunctionContextAuthData(auth, userRecord) {
|
|
|
274
242
|
* @returns
|
|
275
243
|
*/
|
|
276
244
|
function createTestFirestoreTokenForUserRecord(auth, userRecord) {
|
|
277
|
-
|
|
245
|
+
return createEncodedTestFirestoreTokenForUserRecord(auth, userRecord).then(decodeEncodedCreateCustomTokenResult);
|
|
278
246
|
}
|
|
279
247
|
/**
|
|
280
248
|
* Creates an encoded firestore token used for testing.
|
|
@@ -284,167 +252,158 @@ function createTestFirestoreTokenForUserRecord(auth, userRecord) {
|
|
|
284
252
|
* @returns
|
|
285
253
|
*/
|
|
286
254
|
function createEncodedTestFirestoreTokenForUserRecord(auth, userRecord) {
|
|
287
|
-
|
|
288
|
-
|
|
255
|
+
// TODO: Consider replacing createCustomToken, as the custom claims are put into an object called claims in the JWT, instead of spread over. The decodeEncodedCreateCustomTokenResult() function handles this issue, but it may not be expected.
|
|
256
|
+
return auth.createCustomToken(userRecord.uid, testFirestoreClaimsFromUserRecord(userRecord));
|
|
289
257
|
}
|
|
290
258
|
function decodeEncodedCreateCustomTokenResult(token) {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
259
|
+
const decoded = jsonwebtoken.decode(token);
|
|
260
|
+
const decodedToken = {
|
|
261
|
+
...decoded,
|
|
262
|
+
...decoded.claims,
|
|
263
|
+
auth_time: decoded.iat,
|
|
264
|
+
firebase: decoded.claims?.firebase ?? {}
|
|
265
|
+
};
|
|
266
|
+
delete decodedToken.claims; // remove the "claims" item if it exists.
|
|
267
|
+
return decodedToken;
|
|
300
268
|
}
|
|
301
269
|
function testFirestoreClaimsFromUserRecord(userRecord) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
270
|
+
// Copy claims to be similar to DecodedIdToken pieces.
|
|
271
|
+
const baseClaims = {
|
|
272
|
+
picture: userRecord.photoURL,
|
|
273
|
+
email: userRecord.email,
|
|
274
|
+
email_verified: userRecord.emailVerified ?? false,
|
|
275
|
+
firebase: {
|
|
276
|
+
sign_in_provider: '@dereekb/firebase-server/test',
|
|
277
|
+
identities: []
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const customClaims = userRecord.customClaims;
|
|
281
|
+
const claims = {
|
|
282
|
+
...customClaims,
|
|
283
|
+
...baseClaims
|
|
284
|
+
};
|
|
285
|
+
return claims;
|
|
318
286
|
}
|
|
319
287
|
|
|
320
288
|
class ModelTestContextFixture extends test.AbstractChildTestContextFixture {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
289
|
+
// MARK: ModelTestContext (Forwarded)
|
|
290
|
+
get documentId() {
|
|
291
|
+
return this.instance.documentId;
|
|
292
|
+
}
|
|
293
|
+
get documentKey() {
|
|
294
|
+
return this.instance.documentKey;
|
|
295
|
+
}
|
|
296
|
+
get documentFlatKey() {
|
|
297
|
+
return this.instance.documentFlatKey;
|
|
298
|
+
}
|
|
299
|
+
get documentTwoWayFlatKey() {
|
|
300
|
+
return this.instance.documentTwoWayFlatKey;
|
|
301
|
+
}
|
|
302
|
+
get documentRef() {
|
|
303
|
+
return this.instance.documentRef;
|
|
304
|
+
}
|
|
305
|
+
get document() {
|
|
306
|
+
return this.instance.document;
|
|
307
|
+
}
|
|
340
308
|
}
|
|
341
309
|
class ModelTestContextInstance {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
310
|
+
collection;
|
|
311
|
+
ref;
|
|
312
|
+
testContext;
|
|
313
|
+
constructor(collection, ref, testContext) {
|
|
314
|
+
this.collection = collection;
|
|
315
|
+
this.ref = ref;
|
|
316
|
+
this.testContext = testContext;
|
|
317
|
+
}
|
|
318
|
+
get documentId() {
|
|
319
|
+
return this.ref.id;
|
|
320
|
+
}
|
|
321
|
+
get documentKey() {
|
|
322
|
+
return this.ref.path;
|
|
323
|
+
}
|
|
324
|
+
get documentFlatKey() {
|
|
325
|
+
return firebase.flatFirestoreModelKey(this.documentKey);
|
|
326
|
+
}
|
|
327
|
+
get documentTwoWayFlatKey() {
|
|
328
|
+
return firebase.twoWayFlatFirestoreModelKey(this.documentKey);
|
|
329
|
+
}
|
|
330
|
+
get documentRef() {
|
|
331
|
+
return this.ref;
|
|
332
|
+
}
|
|
333
|
+
get document() {
|
|
334
|
+
return this.collection.documentAccessor().loadDocument(this.ref);
|
|
335
|
+
}
|
|
368
336
|
}
|
|
369
337
|
/**
|
|
370
338
|
* Creates a new Test Context that has a random user for authorization for use in firebase server tests.
|
|
371
339
|
*/
|
|
372
340
|
function modelTestContextFactory(config) {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const accessor = collection.documentAccessor();
|
|
378
|
-
if (accessor.newDocument == null) {
|
|
379
|
-
throw new Error('collection passed to makeRef() was not a full FirestoreCollection. Either supply a custom makeRef() function or a FirestoreCollection that has newDocument() available on the documentAccessor.');
|
|
380
|
-
}
|
|
381
|
-
return accessor.newDocument().documentRef;
|
|
382
|
-
},
|
|
383
|
-
makeInstance = (collection, ref, testInstance) => new ModelTestContextInstance(collection, ref, testInstance),
|
|
384
|
-
makeFixture = f => new ModelTestContextFixture(f),
|
|
385
|
-
initDocument,
|
|
386
|
-
destroyInstance
|
|
387
|
-
} = config;
|
|
388
|
-
return (params, buildTests) => {
|
|
389
|
-
const {
|
|
390
|
-
f
|
|
391
|
-
} = params;
|
|
392
|
-
return test.useTestContextFixture({
|
|
393
|
-
fixture: makeFixture(f),
|
|
394
|
-
buildTests,
|
|
395
|
-
initInstance: async () => {
|
|
396
|
-
const parentInstance = f.instance;
|
|
397
|
-
let ref;
|
|
398
|
-
let collection;
|
|
399
|
-
let init;
|
|
400
|
-
if (params.doc) {
|
|
401
|
-
const doc = await util.getValueFromGetter(params.doc);
|
|
402
|
-
if (!collectionForDocument) {
|
|
403
|
-
throw new Error('collectionForDocument() is required when using ModelTestContextDocumentRefParams values as input.');
|
|
404
|
-
}
|
|
405
|
-
collection = collectionForDocument(parentInstance, doc);
|
|
406
|
-
const expectedCollectionName = collection.documentAccessor().modelIdentity.collectionName;
|
|
407
|
-
if (expectedCollectionName !== doc.modelIdentity.collectionName) {
|
|
408
|
-
throw new Error(`Input doc is in a different collection (${doc.modelIdentity.collectionName}) than expected (${expectedCollectionName}).`);
|
|
409
|
-
}
|
|
410
|
-
ref = doc.documentRef;
|
|
411
|
-
init = false;
|
|
412
|
-
} else {
|
|
413
|
-
collection = getCollection(parentInstance, params);
|
|
414
|
-
ref = await makeRef(collection, params, parentInstance);
|
|
415
|
-
init = true;
|
|
416
|
-
}
|
|
417
|
-
const instance = await makeInstance(collection, ref, parentInstance);
|
|
418
|
-
if (init && initDocument) {
|
|
419
|
-
await initDocument(instance, params);
|
|
341
|
+
const { getCollection, collectionForDocument, makeRef = (collection) => {
|
|
342
|
+
const accessor = collection.documentAccessor();
|
|
343
|
+
if (accessor.newDocument == null) {
|
|
344
|
+
throw new Error('collection passed to makeRef() was not a full FirestoreCollection. Either supply a custom makeRef() function or a FirestoreCollection that has newDocument() available on the documentAccessor.');
|
|
420
345
|
}
|
|
421
|
-
return
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
346
|
+
return accessor.newDocument().documentRef;
|
|
347
|
+
}, makeInstance = (collection, ref, testInstance) => new ModelTestContextInstance(collection, ref, testInstance), makeFixture = (f) => new ModelTestContextFixture(f), initDocument, destroyInstance } = config;
|
|
348
|
+
return (params, buildTests) => {
|
|
349
|
+
const { f } = params;
|
|
350
|
+
return test.useTestContextFixture({
|
|
351
|
+
fixture: makeFixture(f),
|
|
352
|
+
buildTests,
|
|
353
|
+
initInstance: async () => {
|
|
354
|
+
const parentInstance = f.instance;
|
|
355
|
+
let ref;
|
|
356
|
+
let collection;
|
|
357
|
+
let init;
|
|
358
|
+
if (params.doc) {
|
|
359
|
+
const doc = await util.getValueFromGetter(params.doc);
|
|
360
|
+
if (!collectionForDocument) {
|
|
361
|
+
throw new Error('collectionForDocument() is required when using ModelTestContextDocumentRefParams values as input.');
|
|
362
|
+
}
|
|
363
|
+
collection = collectionForDocument(parentInstance, doc);
|
|
364
|
+
const expectedCollectionName = collection.documentAccessor().modelIdentity.collectionName;
|
|
365
|
+
if (expectedCollectionName !== doc.modelIdentity.collectionName) {
|
|
366
|
+
throw new Error(`Input doc is in a different collection (${doc.modelIdentity.collectionName}) than expected (${expectedCollectionName}).`);
|
|
367
|
+
}
|
|
368
|
+
ref = doc.documentRef;
|
|
369
|
+
init = false;
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
collection = getCollection(parentInstance, params);
|
|
373
|
+
ref = await makeRef(collection, params, parentInstance);
|
|
374
|
+
init = true;
|
|
375
|
+
}
|
|
376
|
+
const instance = await makeInstance(collection, ref, parentInstance);
|
|
377
|
+
if (init && initDocument) {
|
|
378
|
+
await initDocument(instance, params);
|
|
379
|
+
}
|
|
380
|
+
return instance;
|
|
381
|
+
},
|
|
382
|
+
destroyInstance
|
|
383
|
+
});
|
|
384
|
+
};
|
|
426
385
|
}
|
|
427
386
|
|
|
428
387
|
let adminEnvironmentInitialized = false;
|
|
429
388
|
function isAdminEnvironmentInitialized() {
|
|
430
|
-
|
|
389
|
+
return adminEnvironmentInitialized;
|
|
431
390
|
}
|
|
432
391
|
function generateNewProjectId() {
|
|
433
|
-
|
|
434
|
-
|
|
392
|
+
const projectId = 'firebase-test-' + new Date().getTime();
|
|
393
|
+
return projectId;
|
|
435
394
|
}
|
|
436
395
|
function rollNewGCloudProjectEnvironmentVariable() {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
396
|
+
const projectId = generateNewProjectId();
|
|
397
|
+
process.env.GCLOUD_TEST_PROJECT = projectId;
|
|
398
|
+
process.env.GCLOUD_PROJECT = projectId;
|
|
399
|
+
applyFirebaseGCloudTestProjectIdToFirebaseConfigEnv();
|
|
400
|
+
return projectId;
|
|
442
401
|
}
|
|
443
402
|
function getGCloudProjectId() {
|
|
444
|
-
|
|
403
|
+
return process.env.GCLOUD_PROJECT;
|
|
445
404
|
}
|
|
446
405
|
function getGCloudTestProjectId() {
|
|
447
|
-
|
|
406
|
+
return process.env.GCLOUD_TEST_PROJECT;
|
|
448
407
|
}
|
|
449
408
|
/**
|
|
450
409
|
* Applies the current GCLOUD_PROJECT to FIREBASE_CONFIG.
|
|
@@ -453,53 +412,55 @@ function getGCloudTestProjectId() {
|
|
|
453
412
|
* so that each component can also
|
|
454
413
|
*/
|
|
455
414
|
function applyFirebaseGCloudTestProjectIdToFirebaseConfigEnv() {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
415
|
+
// firebase-functions-test overwrites this each time.
|
|
416
|
+
// https://github.com/firebase/firebase-functions-test/blob/acb068f4c086f3355b2960b9e9e5895716c7f8cc/src/lifecycle.ts#L37
|
|
417
|
+
const testProjectId = getGCloudTestProjectId();
|
|
418
|
+
// console.log('Test project: ', testProjectId);
|
|
419
|
+
if (!testProjectId) {
|
|
420
|
+
throw new Error('No test project id was available in the environment. Did you call initFirebaseAdminTestEnvironment() first?');
|
|
421
|
+
}
|
|
422
|
+
const config = JSON.parse(process.env.FIREBASE_CONFIG ?? '{}');
|
|
423
|
+
config.projectId = testProjectId;
|
|
424
|
+
process.env.FIREBASE_CONFIG = JSON.stringify(config);
|
|
425
|
+
process.env.GCLOUD_PROJECT = testProjectId; // re-apply to GCLOUD_PROJECT too
|
|
426
|
+
return testProjectId;
|
|
468
427
|
}
|
|
469
428
|
/**
|
|
470
429
|
* Should be called before calling/using adminFirebaseTestBuilder(). This should only be called once.
|
|
471
430
|
*/
|
|
472
431
|
function initFirebaseAdminTestEnvironment(config) {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
432
|
+
function crashForEmulator(emulator) {
|
|
433
|
+
throw new Error(`Emulator for ${emulator} was not set null or to a host. Crashing to prevent contamination.`);
|
|
434
|
+
}
|
|
435
|
+
function configureEmulator(emulator, envKey) {
|
|
436
|
+
const emulatorConfig = config.emulators[emulator];
|
|
437
|
+
if (emulatorConfig) {
|
|
438
|
+
process.env[envKey] = emulatorConfig;
|
|
439
|
+
}
|
|
440
|
+
else if (config.emulators.firestore !== null) {
|
|
441
|
+
crashForEmulator(emulator);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
rollNewGCloudProjectEnvironmentVariable();
|
|
445
|
+
configureEmulator('auth', 'FIREBASE_AUTH_EMULATOR_HOST');
|
|
446
|
+
configureEmulator('firestore', 'FIRESTORE_EMULATOR_HOST');
|
|
447
|
+
configureEmulator('storage', 'FIREBASE_STORAGE_EMULATOR_HOST');
|
|
448
|
+
applyFirebaseGCloudTestProjectIdToFirebaseConfigEnv();
|
|
449
|
+
adminEnvironmentInitialized = true;
|
|
490
450
|
}
|
|
491
451
|
|
|
492
452
|
function makeGoogleFirestoreContext(drivers, firestore) {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
453
|
+
const context = firebase.firestoreContextFactory(drivers)(firestore);
|
|
454
|
+
context.drivers = drivers;
|
|
455
|
+
return context;
|
|
496
456
|
}
|
|
497
457
|
class GoogleCloudTestFirestoreInstance extends test$1.TestFirestoreInstance {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
458
|
+
constructor(drivers, firestore) {
|
|
459
|
+
super(makeGoogleFirestoreContext(drivers, firestore));
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
class GoogleCloudTestFirestoreContextFixture extends test$1.TestFirestoreContextFixture {
|
|
501
463
|
}
|
|
502
|
-
class GoogleCloudTestFirestoreContextFixture extends test$1.TestFirestoreContextFixture {}
|
|
503
464
|
let COUNTER$1 = 0;
|
|
504
465
|
/**
|
|
505
466
|
* A TestContextBuilderFunction for building firestore test context factories using @google-cloud/firestore. This means SERVER TESTING ONLY. For client testing, look at @dereekb/firestore.
|
|
@@ -509,44 +470,43 @@ let COUNTER$1 = 0;
|
|
|
509
470
|
* If you need all of Firebase (firebase-admin library), look at adminFirebaseAdminTestBuilder() instead.
|
|
510
471
|
*/
|
|
511
472
|
const googleCloudTestFirestoreBuilder = test.testContextBuilder({
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
473
|
+
buildConfig: (input) => {
|
|
474
|
+
const config = {
|
|
475
|
+
host: input?.host ?? 'localhost',
|
|
476
|
+
port: input?.port ?? 0
|
|
477
|
+
};
|
|
478
|
+
return config;
|
|
479
|
+
},
|
|
480
|
+
buildFixture: () => new GoogleCloudTestFirestoreContextFixture(),
|
|
481
|
+
setupInstance: async (config) => {
|
|
482
|
+
const random = Math.floor(Math.random() * 10000);
|
|
483
|
+
const drivers = test$1.makeTestingFirestoreDrivers(firebaseServer.googleCloudFirestoreDrivers());
|
|
484
|
+
const projectId = `test-${COUNTER$1++}-${Date.now()}-${random}`.substring(0, 30);
|
|
485
|
+
const firestore$1 = new firestore.Firestore({
|
|
486
|
+
projectId,
|
|
487
|
+
host: config.host,
|
|
488
|
+
port: config.port,
|
|
489
|
+
maxIdleChannels: 0
|
|
490
|
+
});
|
|
491
|
+
return new GoogleCloudTestFirestoreInstance(drivers, firestore$1);
|
|
492
|
+
},
|
|
493
|
+
teardownInstance: async (instance, config) => {
|
|
494
|
+
await instance.firestore.terminate();
|
|
495
|
+
}
|
|
535
496
|
});
|
|
536
497
|
|
|
537
498
|
function makeGoogleFirebaseStorageContext(drivers, firebaseStorage, defaultBucketId) {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
context.drivers = drivers;
|
|
542
|
-
return context;
|
|
499
|
+
const context = firebase.firebaseStorageContextFactory(drivers)(firebaseStorage, { defaultBucketId });
|
|
500
|
+
context.drivers = drivers;
|
|
501
|
+
return context;
|
|
543
502
|
}
|
|
544
503
|
class GoogleCloudTestFirebaseStorageInstance extends test$1.TestFirebaseStorageInstance {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
504
|
+
constructor(drivers, firebaseStorage, defaultBucketId) {
|
|
505
|
+
super(makeGoogleFirebaseStorageContext(drivers, firebaseStorage, defaultBucketId));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
class GoogleCloudTestFirebaseStorageContextFixture extends test$1.TestFirebaseStorageContextFixture {
|
|
548
509
|
}
|
|
549
|
-
class GoogleCloudTestFirebaseStorageContextFixture extends test$1.TestFirebaseStorageContextFixture {}
|
|
550
510
|
let COUNTER = 0;
|
|
551
511
|
/**
|
|
552
512
|
* A TestContextBuilderFunction for building firebase storage test context factories using @google-cloud/storage. This means SERVER TESTING ONLY. For client testing, look at @dereekb/firestore.
|
|
@@ -556,136 +516,136 @@ let COUNTER = 0;
|
|
|
556
516
|
* If you need all of Firebase (firebase-admin library), look at adminFirebaseAdminTestBuilder() instead.
|
|
557
517
|
*/
|
|
558
518
|
const googleCloudTestFirebaseStorageBuilder = test.testContextBuilder({
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
519
|
+
buildConfig: (input) => {
|
|
520
|
+
const config = {
|
|
521
|
+
host: input?.host ?? 'localhost',
|
|
522
|
+
port: input?.port ?? 0
|
|
523
|
+
};
|
|
524
|
+
if (!config.port) {
|
|
525
|
+
throw new Error('Port for host is required.');
|
|
526
|
+
}
|
|
527
|
+
return config;
|
|
528
|
+
},
|
|
529
|
+
buildFixture: () => new GoogleCloudTestFirebaseStorageContextFixture(),
|
|
530
|
+
setupInstance: async (config) => {
|
|
531
|
+
const drivers = test$1.makeTestingFirebaseStorageDrivers(firebaseServer.googleCloudFirebaseStorageDrivers());
|
|
532
|
+
const projectId = `firebase-storage-server-test-${new Date().getTime()}-${COUNTER++}`;
|
|
533
|
+
const firebaseStorage = new storage.Storage({
|
|
534
|
+
projectId,
|
|
535
|
+
// ensure http:// is provided so the library doesn't default to/try https://
|
|
536
|
+
apiEndpoint: `http://${config.host}:${config.port}`
|
|
537
|
+
});
|
|
538
|
+
const defaultBucketId = projectId;
|
|
539
|
+
return new GoogleCloudTestFirebaseStorageInstance(drivers, firebaseStorage, defaultBucketId);
|
|
540
|
+
},
|
|
541
|
+
teardownInstance: async (instance, config) => {
|
|
542
|
+
// nothing to teardown
|
|
543
|
+
}
|
|
584
544
|
});
|
|
585
545
|
|
|
586
546
|
class FirebaseAdminTestContextFixture extends test.AbstractTestContextFixture {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
547
|
+
// MARK: FirebaseAdminTestContext (Forwarded)
|
|
548
|
+
get app() {
|
|
549
|
+
return this.instance.app;
|
|
550
|
+
}
|
|
551
|
+
get auth() {
|
|
552
|
+
return this.instance.auth;
|
|
553
|
+
}
|
|
554
|
+
get firestore() {
|
|
555
|
+
return this.instance.firestore;
|
|
556
|
+
}
|
|
557
|
+
get firestoreInstance() {
|
|
558
|
+
return this.instance.firestoreInstance;
|
|
559
|
+
}
|
|
560
|
+
get firestoreContext() {
|
|
561
|
+
return this.instance.firestoreContext;
|
|
562
|
+
}
|
|
563
|
+
get storage() {
|
|
564
|
+
return this.instance.storage;
|
|
565
|
+
}
|
|
566
|
+
get storageInstance() {
|
|
567
|
+
return this.instance.storageInstance;
|
|
568
|
+
}
|
|
569
|
+
get storageContext() {
|
|
570
|
+
return this.instance.storageContext;
|
|
571
|
+
}
|
|
572
|
+
get fnWrapper() {
|
|
573
|
+
return this.instance.fnWrapper;
|
|
574
|
+
}
|
|
615
575
|
}
|
|
616
576
|
// MARK: FirebaseAdminTestBuilder
|
|
617
577
|
class FirebaseAdminTestContextInstance {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
return new GoogleCloudTestFirestoreInstance(drivers, this.firestore);
|
|
578
|
+
app;
|
|
579
|
+
getTestFirestoreInstance = util.cachedGetter(() => {
|
|
580
|
+
const drivers = test$1.makeTestingFirestoreDrivers(firebaseServer.googleCloudFirestoreDrivers());
|
|
581
|
+
return new GoogleCloudTestFirestoreInstance(drivers, this.firestore);
|
|
623
582
|
});
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
583
|
+
getTestFirebaseStorageInstance = util.cachedGetter(() => {
|
|
584
|
+
const drivers = test$1.makeTestingFirebaseStorageDrivers(firebaseServer.googleCloudFirebaseStorageDrivers());
|
|
585
|
+
const defaultBucketId = this.app.options.storageBucket;
|
|
586
|
+
return new GoogleCloudTestFirebaseStorageInstance(drivers, this.storage, defaultBucketId);
|
|
628
587
|
});
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
588
|
+
constructor(app) {
|
|
589
|
+
this.app = app;
|
|
590
|
+
}
|
|
591
|
+
get auth() {
|
|
592
|
+
return this.app.auth();
|
|
593
|
+
}
|
|
594
|
+
get firestore() {
|
|
595
|
+
return this.app.firestore();
|
|
596
|
+
}
|
|
597
|
+
get firestoreInstance() {
|
|
598
|
+
return this.getTestFirestoreInstance();
|
|
599
|
+
}
|
|
600
|
+
get firestoreContext() {
|
|
601
|
+
return this.firestoreInstance.firestoreContext;
|
|
602
|
+
}
|
|
603
|
+
get storage() {
|
|
604
|
+
return firebaseServer.googleCloudStorageFromFirebaseAdminStorage(this.app.storage());
|
|
605
|
+
}
|
|
606
|
+
get storageInstance() {
|
|
607
|
+
return this.getTestFirebaseStorageInstance();
|
|
608
|
+
}
|
|
609
|
+
get storageContext() {
|
|
610
|
+
return this.storageInstance.storageContext;
|
|
611
|
+
}
|
|
612
|
+
get fnWrapper() {
|
|
613
|
+
throw new Error('wrapCloudFunction is unsupported by this type.');
|
|
614
|
+
}
|
|
655
615
|
}
|
|
656
616
|
class AbstractFirebaseAdminTestContextInstanceChild {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
617
|
+
parent;
|
|
618
|
+
constructor(parent) {
|
|
619
|
+
this.parent = parent;
|
|
620
|
+
}
|
|
621
|
+
// MARK: FirebaseAdminTestContext (Forwarded)
|
|
622
|
+
get app() {
|
|
623
|
+
return this.parent.app;
|
|
624
|
+
}
|
|
625
|
+
get auth() {
|
|
626
|
+
return this.parent.auth;
|
|
627
|
+
}
|
|
628
|
+
get firestore() {
|
|
629
|
+
return this.parent.firestore;
|
|
630
|
+
}
|
|
631
|
+
get firestoreInstance() {
|
|
632
|
+
return this.parent.firestoreInstance;
|
|
633
|
+
}
|
|
634
|
+
get firestoreContext() {
|
|
635
|
+
return this.parent.firestoreContext;
|
|
636
|
+
}
|
|
637
|
+
get storage() {
|
|
638
|
+
return this.parent.storage;
|
|
639
|
+
}
|
|
640
|
+
get storageInstance() {
|
|
641
|
+
return this.parent.storageInstance;
|
|
642
|
+
}
|
|
643
|
+
get storageContext() {
|
|
644
|
+
return this.parent.storageContext;
|
|
645
|
+
}
|
|
646
|
+
get fnWrapper() {
|
|
647
|
+
return this.parent.fnWrapper;
|
|
648
|
+
}
|
|
689
649
|
}
|
|
690
650
|
/**
|
|
691
651
|
* A TestContextBuilderFunction for building firebase test context factories using firebase-admin.
|
|
@@ -693,28 +653,25 @@ class AbstractFirebaseAdminTestContextInstanceChild {
|
|
|
693
653
|
* This can be used to easily build a testing context that sets up RulesTestEnvironment for tests that sets itself up and tears itself down.
|
|
694
654
|
*/
|
|
695
655
|
const firebaseAdminTestBuilder = test.testContextBuilder({
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
656
|
+
buildConfig: (input) => {
|
|
657
|
+
const config = {
|
|
658
|
+
...input
|
|
659
|
+
};
|
|
660
|
+
return config;
|
|
661
|
+
},
|
|
662
|
+
buildFixture: () => new FirebaseAdminTestContextFixture(),
|
|
663
|
+
setupInstance: async (config) => {
|
|
664
|
+
if (!isAdminEnvironmentInitialized()) {
|
|
665
|
+
throw new Error('Call initFirebaseAdminTestEnvironment() from @dereekb/firebase-server was not called before using adminFirebaseTestBuilder().');
|
|
666
|
+
}
|
|
667
|
+
const projectId = generateNewProjectId();
|
|
668
|
+
const storageBucket = 'b-' + projectId;
|
|
669
|
+
const app = admin.initializeApp({ projectId, storageBucket });
|
|
670
|
+
return new FirebaseAdminTestContextInstance(app);
|
|
671
|
+
},
|
|
672
|
+
teardownInstance: async (instance, config) => {
|
|
673
|
+
await instance.app.delete(); // clean up the instance
|
|
706
674
|
}
|
|
707
|
-
const projectId = generateNewProjectId();
|
|
708
|
-
const storageBucket = 'b-' + projectId;
|
|
709
|
-
const app = admin.initializeApp({
|
|
710
|
-
projectId,
|
|
711
|
-
storageBucket
|
|
712
|
-
});
|
|
713
|
-
return new FirebaseAdminTestContextInstance(app);
|
|
714
|
-
},
|
|
715
|
-
teardownInstance: async (instance, config) => {
|
|
716
|
-
await instance.app.delete(); // clean up the instance
|
|
717
|
-
}
|
|
718
675
|
});
|
|
719
676
|
const firebaseAdminTestContextFactory = firebaseAdminTestBuilder({});
|
|
720
677
|
// MARK: Firestore Context
|
|
@@ -727,66 +684,66 @@ const firebaseAdminTestContextFactory = firebaseAdminTestBuilder({});
|
|
|
727
684
|
* @returns
|
|
728
685
|
*/
|
|
729
686
|
function firebaseAdminFirestoreContextFixture(factory) {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
687
|
+
return (buildTests) => {
|
|
688
|
+
factory((f) => firebaseAdminFirestoreContextWithFixture(f, buildTests));
|
|
689
|
+
};
|
|
733
690
|
}
|
|
734
691
|
function firebaseAdminFirestoreContextWithFixture(f, buildTests) {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
692
|
+
test.useTestContextFixture({
|
|
693
|
+
fixture: new test$1.TestFirestoreContextFixture(),
|
|
694
|
+
/**
|
|
695
|
+
* Build tests by passing the fixture to the testing functions.
|
|
696
|
+
*
|
|
697
|
+
* This will inject all tests and sub testing lifecycle items.
|
|
698
|
+
*/
|
|
699
|
+
buildTests,
|
|
700
|
+
initInstance: () => f.instance.getTestFirestoreInstance()
|
|
701
|
+
});
|
|
745
702
|
}
|
|
746
703
|
|
|
747
704
|
function firebaseAdminCloudFunctionWrapper(instance) {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
705
|
+
const wrapV1CloudFunction = (x) => {
|
|
706
|
+
return instance.wrap(x);
|
|
707
|
+
};
|
|
708
|
+
const wrapV2CallableRequest = (x) => {
|
|
709
|
+
const wrappedCloudFunction = instance.wrap(x);
|
|
710
|
+
// context is marked optional here to better match the gen 1 callable function signature
|
|
711
|
+
return async (data, context) => {
|
|
712
|
+
const request = {
|
|
713
|
+
...context,
|
|
714
|
+
data,
|
|
715
|
+
// NOTE: These will typically not be used/available as they are express.js properties that are not available or useful to the handlers
|
|
716
|
+
rawRequest: context?.rawRequest ?? {},
|
|
717
|
+
acceptsStreaming: false
|
|
718
|
+
};
|
|
719
|
+
const result = (await wrappedCloudFunction(request));
|
|
720
|
+
return result;
|
|
721
|
+
};
|
|
722
|
+
};
|
|
723
|
+
const wrapV2CloudFunction = (x) => {
|
|
724
|
+
return instance.wrap(x);
|
|
725
|
+
};
|
|
726
|
+
const wrapBlockingFunction = ((blockingFunction) => {
|
|
727
|
+
return instance.wrap(blockingFunction);
|
|
728
|
+
});
|
|
729
|
+
const wrapCloudFunction = (x) => {
|
|
730
|
+
return instance.wrap(x);
|
|
731
|
+
};
|
|
732
|
+
const wrapper = {
|
|
733
|
+
wrapV1CloudFunction,
|
|
734
|
+
wrapV2CloudFunction,
|
|
735
|
+
wrapV2CallableRequest,
|
|
736
|
+
wrapCallableRequest: wrapV2CallableRequest,
|
|
737
|
+
wrapBlockingFunction,
|
|
738
|
+
wrapCloudFunction
|
|
764
739
|
};
|
|
765
|
-
|
|
766
|
-
const wrapV2CloudFunction = x => {
|
|
767
|
-
return instance.wrap(x);
|
|
768
|
-
};
|
|
769
|
-
const wrapBlockingFunction = blockingFunction => {
|
|
770
|
-
return instance.wrap(blockingFunction);
|
|
771
|
-
};
|
|
772
|
-
const wrapCloudFunction = x => {
|
|
773
|
-
return instance.wrap(x);
|
|
774
|
-
};
|
|
775
|
-
const wrapper = {
|
|
776
|
-
wrapV1CloudFunction,
|
|
777
|
-
wrapV2CloudFunction,
|
|
778
|
-
wrapV2CallableRequest,
|
|
779
|
-
wrapCallableRequest: wrapV2CallableRequest,
|
|
780
|
-
wrapBlockingFunction,
|
|
781
|
-
wrapCloudFunction
|
|
782
|
-
};
|
|
783
|
-
return wrapper;
|
|
740
|
+
return wrapper;
|
|
784
741
|
}
|
|
785
742
|
function wrapCloudFunctionV1ForTests(wrapper, getter) {
|
|
786
|
-
|
|
743
|
+
return () => wrapper.wrapV1CloudFunction(getter());
|
|
787
744
|
}
|
|
788
745
|
function wrapCallableRequestForTests(wrapper, getter) {
|
|
789
|
-
|
|
746
|
+
return () => wrapper.wrapCallableRequest(getter());
|
|
790
747
|
}
|
|
791
748
|
|
|
792
749
|
// MARK: FirebaseAdminFunctionTestBuilder
|
|
@@ -796,68 +753,69 @@ let functionsInitialized = false;
|
|
|
796
753
|
*/
|
|
797
754
|
let firebaseFunctionsTestInstance;
|
|
798
755
|
function setupFirebaseAdminFunctionTestSingleton(reroll = false) {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
756
|
+
if (!isAdminEnvironmentInitialized()) {
|
|
757
|
+
throw new Error('initFirebaseAdminTestEnvironment() was not called.');
|
|
758
|
+
}
|
|
759
|
+
if (firebaseFunctionsTestInstance) {
|
|
760
|
+
firebaseFunctionsTestInstance.cleanup(); // destroy the old instance if it is up.
|
|
761
|
+
}
|
|
762
|
+
firebaseFunctionsTestInstance = functions();
|
|
763
|
+
if (reroll) {
|
|
764
|
+
rollNewGCloudProjectEnvironmentVariable();
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
applyFirebaseGCloudTestProjectIdToFirebaseConfigEnv();
|
|
768
|
+
}
|
|
769
|
+
functionsInitialized = true;
|
|
770
|
+
return firebaseFunctionsTestInstance;
|
|
813
771
|
}
|
|
814
772
|
function rerollFirebaseAdminFunctionTestSingleton() {
|
|
815
|
-
|
|
773
|
+
return setupFirebaseAdminFunctionTestSingleton(true);
|
|
816
774
|
}
|
|
817
775
|
class FirebaseAdminFunctionTestContextFixture extends test.AbstractTestContextFixture {
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
776
|
+
// MARK: FirebaseAdminTestContext (Forwarded)
|
|
777
|
+
get app() {
|
|
778
|
+
return this.instance.app;
|
|
779
|
+
}
|
|
780
|
+
get auth() {
|
|
781
|
+
return this.instance.auth;
|
|
782
|
+
}
|
|
783
|
+
get firestore() {
|
|
784
|
+
return this.instance.firestore;
|
|
785
|
+
}
|
|
786
|
+
get firestoreInstance() {
|
|
787
|
+
return this.instance.firestoreInstance;
|
|
788
|
+
}
|
|
789
|
+
get firestoreContext() {
|
|
790
|
+
return this.instance.firestoreContext;
|
|
791
|
+
}
|
|
792
|
+
get storage() {
|
|
793
|
+
return this.instance.storage;
|
|
794
|
+
}
|
|
795
|
+
get storageInstance() {
|
|
796
|
+
return this.instance.storageInstance;
|
|
797
|
+
}
|
|
798
|
+
get storageContext() {
|
|
799
|
+
return this.instance.storageContext;
|
|
800
|
+
}
|
|
801
|
+
get fnWrapper() {
|
|
802
|
+
return this.instance.fnWrapper;
|
|
803
|
+
}
|
|
846
804
|
}
|
|
847
805
|
class FirebaseAdminFunctionTestContextInstance extends FirebaseAdminTestContextInstance {
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
806
|
+
instance;
|
|
807
|
+
_fnWrapper = util.cachedGetter(() => firebaseAdminCloudFunctionWrapper(this.instance));
|
|
808
|
+
constructor(instance, app) {
|
|
809
|
+
super(app);
|
|
810
|
+
this.instance = instance;
|
|
811
|
+
}
|
|
812
|
+
get fnWrapper() {
|
|
813
|
+
return this._fnWrapper();
|
|
814
|
+
}
|
|
857
815
|
}
|
|
858
816
|
exports.DEFAULT_FIREBASE_ADMIN_FUNCTION_TEST_USE_FUNCTION_SINGLETON_CONTEXT = false;
|
|
859
817
|
function setDefaultFirebaseAdminFunctionTestUseFunctionSingleton(use) {
|
|
860
|
-
|
|
818
|
+
exports.DEFAULT_FIREBASE_ADMIN_FUNCTION_TEST_USE_FUNCTION_SINGLETON_CONTEXT = use;
|
|
861
819
|
}
|
|
862
820
|
/**
|
|
863
821
|
* A TestContextBuilderFunction for building firebase test context factories using firebase-admin.
|
|
@@ -865,320 +823,296 @@ function setDefaultFirebaseAdminFunctionTestUseFunctionSingleton(use) {
|
|
|
865
823
|
* This can be used to easily build a testing context that sets up RulesTestEnvironment for tests that sets itself up and tears itself down.
|
|
866
824
|
*/
|
|
867
825
|
const firebaseAdminFunctionTestBuilder = test.testContextBuilder({
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
}
|
|
905
|
-
}
|
|
826
|
+
buildConfig: (input) => {
|
|
827
|
+
const config = {
|
|
828
|
+
...input,
|
|
829
|
+
useFunctionSingletonContext: input?.useFunctionSingletonContext ?? exports.DEFAULT_FIREBASE_ADMIN_FUNCTION_TEST_USE_FUNCTION_SINGLETON_CONTEXT
|
|
830
|
+
};
|
|
831
|
+
return config;
|
|
832
|
+
},
|
|
833
|
+
buildFixture: () => new FirebaseAdminFunctionTestContextFixture(),
|
|
834
|
+
setupInstance: async (config) => {
|
|
835
|
+
if (!isAdminEnvironmentInitialized()) {
|
|
836
|
+
throw new Error('initFirebaseAdminTestEnvironment() (in @dereekb/firebase-server package) was not called before using adminFirebaseTestBuilder().');
|
|
837
|
+
}
|
|
838
|
+
if (config.useFunctionSingletonContext) {
|
|
839
|
+
if (!functionsInitialized) {
|
|
840
|
+
throw new Error('Call setupFirebaseAdminFunctionTestSingleton() (in @dereekb/firebase-server package) if using functions in a singleton context (useFunctionSingletonContext = true/undefined).');
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
else if (config.useFunctionSingletonContext === false) {
|
|
844
|
+
firebaseFunctionsTestInstance = rerollFirebaseAdminFunctionTestSingleton();
|
|
845
|
+
}
|
|
846
|
+
const projectId = getGCloudTestProjectId();
|
|
847
|
+
const storageBucket = 'b-' + projectId;
|
|
848
|
+
const app = admin.initializeApp({ projectId, storageBucket });
|
|
849
|
+
return new FirebaseAdminFunctionTestContextInstance(firebaseFunctionsTestInstance, app);
|
|
850
|
+
},
|
|
851
|
+
teardownInstance: async (instance, config) => {
|
|
852
|
+
if (config.useFunctionSingletonContext === false) {
|
|
853
|
+
try {
|
|
854
|
+
await instance.app.delete(); // will be called in cleanup
|
|
855
|
+
firebaseFunctionsTestInstance.cleanup();
|
|
856
|
+
}
|
|
857
|
+
catch (e) {
|
|
858
|
+
// do nothing
|
|
859
|
+
}
|
|
860
|
+
firebaseFunctionsTestInstance = undefined;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
906
863
|
});
|
|
907
864
|
const firebaseAdminFunctionTestContextFactory = firebaseAdminFunctionTestBuilder({});
|
|
908
865
|
|
|
909
866
|
class FirebaseAdminNestTestContextFixture extends test.AbstractChildTestContextFixture {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
867
|
+
// MARK: Forwarded
|
|
868
|
+
get nest() {
|
|
869
|
+
return this.instance.nest;
|
|
870
|
+
}
|
|
871
|
+
get nestAppPromiseGetter() {
|
|
872
|
+
return this.instance.nestAppPromiseGetter;
|
|
873
|
+
}
|
|
874
|
+
get(typeOrToken, options) {
|
|
875
|
+
return this.instance.get(typeOrToken, options);
|
|
876
|
+
}
|
|
920
877
|
}
|
|
921
878
|
class FirebaseAdminNestTestContextInstance extends AbstractFirebaseAdminTestContextInstanceChild {
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
879
|
+
nest;
|
|
880
|
+
nestAppPromiseGetter = () => Promise.resolve(this.nest);
|
|
881
|
+
constructor(parent, nest) {
|
|
882
|
+
super(parent);
|
|
883
|
+
this.nest = nest;
|
|
884
|
+
}
|
|
885
|
+
get(typeOrToken, options) {
|
|
886
|
+
return options ? this.nest.get(typeOrToken, options) : this.nest.get(typeOrToken);
|
|
887
|
+
}
|
|
931
888
|
}
|
|
932
889
|
function firebaseAdminNestContextFixture(config, factory) {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
890
|
+
return (buildTests) => {
|
|
891
|
+
factory((f) => firebaseAdminNestContextWithFixture(config, f, buildTests));
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
class FirebaseAdminNestRootModule {
|
|
936
895
|
}
|
|
937
|
-
class FirebaseAdminNestRootModule {}
|
|
938
896
|
function firebaseAdminNestContextWithFixture(config, f, buildTests) {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
897
|
+
const { nestModules, makeProviders = () => [], forceStorageBucket = false, defaultStorageBucket: inputDefaultStorageBucket, envConfig, injectFirebaseServerAppTokenProvider, injectServerEnvServiceProvider, makeFixture = (parent) => new FirebaseAdminNestTestContextFixture(parent), makeInstance = (instance, nest) => new FirebaseAdminNestTestContextInstance(instance, nest), initInstance } = config;
|
|
898
|
+
test.useTestContextFixture({
|
|
899
|
+
fixture: makeFixture(f),
|
|
900
|
+
/**
|
|
901
|
+
* Build tests by passing the fixture to the testing functions.
|
|
902
|
+
*
|
|
903
|
+
* This will inject all tests and sub Jest lifecycle items.
|
|
904
|
+
*/
|
|
905
|
+
buildTests,
|
|
906
|
+
initInstance: async () => {
|
|
907
|
+
const imports = util.asArray(nestModules);
|
|
908
|
+
const providers = makeProviders(f.instance) ?? [];
|
|
909
|
+
const defaultStorageBucket = inputDefaultStorageBucket ?? f.instance.app.options.storageBucket;
|
|
910
|
+
// Inject the serverEnvTokenProvider and optionally the FirebaseServerEnvService
|
|
911
|
+
if (injectServerEnvServiceProvider !== false || envConfig != null) {
|
|
912
|
+
providers.push(nestjs.serverEnvTokenProvider(envConfig || { production: false }));
|
|
913
|
+
if (injectServerEnvServiceProvider !== false) {
|
|
914
|
+
providers.push({
|
|
915
|
+
provide: firebaseServer.FirebaseServerEnvService,
|
|
916
|
+
useClass: firebaseServer.DefaultFirebaseServerEnvService
|
|
917
|
+
}, {
|
|
918
|
+
provide: nestjs.ServerEnvironmentService,
|
|
919
|
+
useExisting: firebaseServer.FirebaseServerEnvService
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
// Inject the firebaseServerAppTokenProvider
|
|
924
|
+
if (injectFirebaseServerAppTokenProvider) {
|
|
925
|
+
providers.push(firebaseServer.firebaseServerAppTokenProvider(util.asGetter(f.instance.app)));
|
|
926
|
+
}
|
|
927
|
+
if (defaultStorageBucket) {
|
|
928
|
+
providers.push(firebaseServer.firebaseServerStorageDefaultBucketIdTokenProvider({
|
|
929
|
+
defaultBucketId: defaultStorageBucket,
|
|
930
|
+
forceBucket: forceStorageBucket
|
|
931
|
+
}));
|
|
932
|
+
}
|
|
933
|
+
const rootModule = {
|
|
934
|
+
module: FirebaseAdminNestRootModule,
|
|
935
|
+
providers,
|
|
936
|
+
exports: providers,
|
|
937
|
+
global: true
|
|
938
|
+
};
|
|
939
|
+
const builder = testing.Test.createTestingModule({
|
|
940
|
+
imports: [rootModule, ...imports]
|
|
941
|
+
});
|
|
942
|
+
const nest = await builder.compile();
|
|
943
|
+
const instance = makeInstance(f.instance, nest);
|
|
944
|
+
if (initInstance) {
|
|
945
|
+
await initInstance(instance);
|
|
946
|
+
}
|
|
947
|
+
return instance;
|
|
948
|
+
},
|
|
949
|
+
destroyInstance: async (instance) => {
|
|
950
|
+
await instance.nest.close();
|
|
976
951
|
}
|
|
977
|
-
|
|
978
|
-
// Inject the firebaseServerAppTokenProvider
|
|
979
|
-
if (injectFirebaseServerAppTokenProvider) {
|
|
980
|
-
providers.push(firebaseServer.firebaseServerAppTokenProvider(util.asGetter(f.instance.app)));
|
|
981
|
-
}
|
|
982
|
-
if (defaultStorageBucket) {
|
|
983
|
-
providers.push(firebaseServer.firebaseServerStorageDefaultBucketIdTokenProvider({
|
|
984
|
-
defaultBucketId: defaultStorageBucket,
|
|
985
|
-
forceBucket: forceStorageBucket
|
|
986
|
-
}));
|
|
987
|
-
}
|
|
988
|
-
const rootModule = {
|
|
989
|
-
module: FirebaseAdminNestRootModule,
|
|
990
|
-
providers,
|
|
991
|
-
exports: providers,
|
|
992
|
-
global: true
|
|
993
|
-
};
|
|
994
|
-
const builder = testing.Test.createTestingModule({
|
|
995
|
-
imports: [rootModule, ...imports]
|
|
996
|
-
});
|
|
997
|
-
const nest = await builder.compile();
|
|
998
|
-
const instance = makeInstance(f.instance, nest);
|
|
999
|
-
if (initInstance) {
|
|
1000
|
-
await initInstance(instance);
|
|
1001
|
-
}
|
|
1002
|
-
return instance;
|
|
1003
|
-
},
|
|
1004
|
-
destroyInstance: async instance => {
|
|
1005
|
-
await instance.nest.close();
|
|
1006
|
-
}
|
|
1007
|
-
});
|
|
952
|
+
});
|
|
1008
953
|
}
|
|
1009
954
|
function firebaseAdminNestContextFactory(config) {
|
|
1010
|
-
|
|
955
|
+
return firebaseAdminNestContextFixture(config, firebaseAdminTestContextFactory);
|
|
1011
956
|
}
|
|
1012
957
|
|
|
1013
958
|
function wrapCloudFunctionForNestTestsGetter(wrapper, fn) {
|
|
1014
|
-
|
|
959
|
+
return wrapCloudFunctionV1ForTests(wrapper.fnWrapper, () => fn(wrapper.nestAppPromiseGetter));
|
|
1015
960
|
}
|
|
1016
961
|
function wrapCallableRequestForNestTestsGetter(wrapper, fn) {
|
|
1017
|
-
|
|
962
|
+
return wrapCallableRequestForTests(wrapper.fnWrapper, () => fn(wrapper.nestAppPromiseGetter));
|
|
1018
963
|
}
|
|
1019
964
|
class FirebaseAdminFunctionNestTestContextFixture extends FirebaseAdminNestTestContextFixture {
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
965
|
+
// MARK: FirebaseAdminTestContext (Forwarded)
|
|
966
|
+
wrapCloudFunctionForNestTests(fn) {
|
|
967
|
+
return this.wrapCloudFunctionForNestTestsGetter(fn)();
|
|
968
|
+
}
|
|
969
|
+
wrapCloudFunctionForNestTestsGetter(fn) {
|
|
970
|
+
return wrapCloudFunctionForNestTestsGetter(this, fn);
|
|
971
|
+
}
|
|
972
|
+
wrapCallableRequestForNestTests(fn) {
|
|
973
|
+
return this.wrapCallableRequestForNestTestsGetter(fn)();
|
|
974
|
+
}
|
|
975
|
+
wrapCallableRequestForNestTestsGetter(fn) {
|
|
976
|
+
return wrapCallableRequestForNestTestsGetter(this, fn);
|
|
977
|
+
}
|
|
978
|
+
// MARK: FirebaseAdminCloudFunctionWrapperSource
|
|
979
|
+
get fnWrapper() {
|
|
980
|
+
return this.parent.instance.fnWrapper;
|
|
981
|
+
}
|
|
1037
982
|
}
|
|
1038
983
|
class FirebaseAdminFunctionNestTestContextInstance extends FirebaseAdminNestTestContextInstance {
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
984
|
+
// MARK: FirebaseAdminTestContext (Forwarded)
|
|
985
|
+
get fnWrapper() {
|
|
986
|
+
return this.parent.fnWrapper;
|
|
987
|
+
}
|
|
1043
988
|
}
|
|
1044
989
|
function firebaseAdminFunctionNestContextFixture(config, factory) {
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
990
|
+
return (buildTests) => {
|
|
991
|
+
factory((f) => firebaseAdminFunctionNestContextWithFixture(config, f, buildTests));
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
class FirebaseAdminFunctionNestRootModule {
|
|
1048
995
|
}
|
|
1049
|
-
class FirebaseAdminFunctionNestRootModule {}
|
|
1050
996
|
function firebaseAdminFunctionNestContextWithFixture(config, f, buildTests) {
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
997
|
+
const mergedConfig = {
|
|
998
|
+
makeFixture: (parent) => new FirebaseAdminFunctionNestTestContextFixture(parent),
|
|
999
|
+
makeInstance: (instance, nest) => new FirebaseAdminFunctionNestTestContextInstance(instance, nest),
|
|
1000
|
+
...config
|
|
1001
|
+
};
|
|
1002
|
+
return firebaseAdminNestContextWithFixture(mergedConfig, f, buildTests);
|
|
1057
1003
|
}
|
|
1058
1004
|
function firebaseAdminFunctionNestContextFactory(config) {
|
|
1059
|
-
|
|
1005
|
+
return firebaseAdminFunctionNestContextFixture(config, firebaseAdminFunctionTestContextFactory);
|
|
1060
1006
|
}
|
|
1061
1007
|
|
|
1062
1008
|
const CallableRequestTestMultipleFixtureSuffix = 'WrappedFn';
|
|
1063
1009
|
function isCallableRequestTestSingleConfig(config) {
|
|
1064
|
-
|
|
1065
|
-
|
|
1010
|
+
const isSingle = Boolean(config.fn);
|
|
1011
|
+
return isSingle;
|
|
1066
1012
|
}
|
|
1067
1013
|
function callableRequestTest(config, buildTests) {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
});
|
|
1089
|
-
test.useTestFunctionMapFixture({
|
|
1090
|
-
fns
|
|
1091
|
-
}, buildTests);
|
|
1092
|
-
}
|
|
1014
|
+
if (isCallableRequestTestSingleConfig(config)) {
|
|
1015
|
+
const { f, fn } = config;
|
|
1016
|
+
test.useTestFunctionFixture({
|
|
1017
|
+
fn: () => {
|
|
1018
|
+
const x = wrapCallableRequestForNestTestsGetter(f, fn)();
|
|
1019
|
+
return x;
|
|
1020
|
+
}
|
|
1021
|
+
}, buildTests);
|
|
1022
|
+
}
|
|
1023
|
+
else {
|
|
1024
|
+
const { f, fns: inputFns } = config;
|
|
1025
|
+
const mappedFns = util.mapObjectMap(inputFns, (fn) => () => wrapCallableRequestForNestTestsGetter(f, fn)());
|
|
1026
|
+
const fns = {};
|
|
1027
|
+
Object.keys(mappedFns).forEach((key) => {
|
|
1028
|
+
fns[`${key}${CallableRequestTestMultipleFixtureSuffix}`] = mappedFns[key];
|
|
1029
|
+
});
|
|
1030
|
+
test.useTestFunctionMapFixture({
|
|
1031
|
+
fns
|
|
1032
|
+
}, buildTests);
|
|
1033
|
+
}
|
|
1093
1034
|
}
|
|
1094
1035
|
function describeCallableRequestTest(label, config, buildTests) {
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1036
|
+
describe(label, () => {
|
|
1037
|
+
callableRequestTest(config, buildTests);
|
|
1038
|
+
});
|
|
1098
1039
|
}
|
|
1099
1040
|
|
|
1100
1041
|
function isCloudFunctionTestSingleConfig(config) {
|
|
1101
|
-
|
|
1102
|
-
|
|
1042
|
+
const isSingle = Boolean(config.fn);
|
|
1043
|
+
return isSingle;
|
|
1103
1044
|
}
|
|
1104
1045
|
function cloudFunctionTest(config, buildTests) {
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
});
|
|
1126
|
-
test.useTestFunctionMapFixture({
|
|
1127
|
-
fns
|
|
1128
|
-
}, buildTests);
|
|
1129
|
-
}
|
|
1046
|
+
if (isCloudFunctionTestSingleConfig(config)) {
|
|
1047
|
+
const { f, fn } = config;
|
|
1048
|
+
test.useTestFunctionFixture({
|
|
1049
|
+
fn: () => {
|
|
1050
|
+
const x = wrapCloudFunctionForNestTestsGetter(f, fn)();
|
|
1051
|
+
return x;
|
|
1052
|
+
}
|
|
1053
|
+
}, buildTests);
|
|
1054
|
+
}
|
|
1055
|
+
else {
|
|
1056
|
+
const { f, fns: inputFns } = config;
|
|
1057
|
+
const mappedFns = util.mapObjectMap(inputFns, (fn) => () => wrapCloudFunctionForNestTestsGetter(f, fn)());
|
|
1058
|
+
const fns = {};
|
|
1059
|
+
Object.keys(mappedFns).forEach((key) => {
|
|
1060
|
+
fns[`${key}CloudFn`] = mappedFns[key];
|
|
1061
|
+
});
|
|
1062
|
+
test.useTestFunctionMapFixture({
|
|
1063
|
+
fns
|
|
1064
|
+
}, buildTests);
|
|
1065
|
+
}
|
|
1130
1066
|
}
|
|
1131
1067
|
function describeCloudFunctionTest(label, config, buildTests) {
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1068
|
+
describe(label, () => {
|
|
1069
|
+
cloudFunctionTest(config, buildTests);
|
|
1070
|
+
});
|
|
1135
1071
|
}
|
|
1136
1072
|
|
|
1137
1073
|
function initFirebaseServerAdminTestEnvironment() {
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1074
|
+
initFirebaseAdminTestEnvironment({
|
|
1075
|
+
emulators: {
|
|
1076
|
+
auth: '0.0.0.0:9903',
|
|
1077
|
+
firestore: '0.0.0.0:9904',
|
|
1078
|
+
storage: '0.0.0.0:9906'
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1145
1081
|
}
|
|
1146
1082
|
function describeFirestoreTest(s) {
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1083
|
+
let collection;
|
|
1084
|
+
beforeEach(() => {
|
|
1085
|
+
collection = test$1.mockItemFirestoreCollection(s.firestoreContext);
|
|
1086
|
+
});
|
|
1087
|
+
describe('firestore', () => {
|
|
1088
|
+
it('should interact with the firestore.', async () => {
|
|
1089
|
+
const document = collection.documentAccessor().newDocument();
|
|
1090
|
+
const setData = {
|
|
1091
|
+
value: 'a',
|
|
1092
|
+
test: true
|
|
1093
|
+
};
|
|
1094
|
+
await document.accessor.set(setData);
|
|
1095
|
+
const exists = await document.accessor.exists();
|
|
1096
|
+
expect(exists).toBe(true);
|
|
1097
|
+
const snapshot = await document.accessor.get();
|
|
1098
|
+
const data = snapshot.data();
|
|
1099
|
+
expect(data).toBeDefined();
|
|
1100
|
+
});
|
|
1164
1101
|
});
|
|
1165
|
-
});
|
|
1166
1102
|
}
|
|
1167
1103
|
|
|
1168
1104
|
/**
|
|
1169
1105
|
* Error thrown when the error type was different than the expected type.
|
|
1170
1106
|
*/
|
|
1171
1107
|
class ExpectedHttpErrorWithSpecificServerErrorCode extends makeError.BaseError {
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
this.expectedErrorCode = expectedErrorCode;
|
|
1181
|
-
}
|
|
1108
|
+
httpError;
|
|
1109
|
+
expectedErrorCode;
|
|
1110
|
+
constructor(httpError, expectedErrorCode) {
|
|
1111
|
+
const { code } = httpError.details;
|
|
1112
|
+
super(`Expected HttpError with an error code of "${expectedErrorCode}", but recieved "${code}" instead.`);
|
|
1113
|
+
this.httpError = httpError;
|
|
1114
|
+
this.expectedErrorCode = expectedErrorCode;
|
|
1115
|
+
}
|
|
1182
1116
|
}
|
|
1183
1117
|
/**
|
|
1184
1118
|
* Creates a ExpectFailAssertionFunction that asserts the encountered error is of the expected type using the instanceof keyword.
|
|
@@ -1190,25 +1124,25 @@ class ExpectedHttpErrorWithSpecificServerErrorCode extends makeError.BaseError {
|
|
|
1190
1124
|
* @returns
|
|
1191
1125
|
*/
|
|
1192
1126
|
function expectFailAssertHttpErrorServerErrorCode(expectedCode) {
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
};
|
|
1127
|
+
return (error) => {
|
|
1128
|
+
if (error instanceof https.HttpsError) {
|
|
1129
|
+
const { code } = error.details;
|
|
1130
|
+
if (code !== expectedCode) {
|
|
1131
|
+
throw new ExpectedHttpErrorWithSpecificServerErrorCode(error, expectedCode);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
else {
|
|
1135
|
+
throw new test.ExpectedErrorOfSpecificTypeError(error, https.HttpsError);
|
|
1136
|
+
}
|
|
1137
|
+
return true;
|
|
1138
|
+
};
|
|
1206
1139
|
}
|
|
1207
1140
|
// MARK: Compat
|
|
1208
1141
|
/**
|
|
1209
1142
|
* @deprecated Use ExpectedHttpErrorWithSpecificServerErrorCode from shared instead. This is kept for backwards compatibility.
|
|
1210
1143
|
*/
|
|
1211
|
-
class JestExpectedHttpErrorWithSpecificServerErrorCode extends ExpectedHttpErrorWithSpecificServerErrorCode {
|
|
1144
|
+
class JestExpectedHttpErrorWithSpecificServerErrorCode extends ExpectedHttpErrorWithSpecificServerErrorCode {
|
|
1145
|
+
}
|
|
1212
1146
|
/**
|
|
1213
1147
|
* @deprecated Use expectFailAssertHttpErrorServerErrorCode from shared instead. This is kept for backwards compatibility.
|
|
1214
1148
|
*/
|
|
@@ -1220,8 +1154,8 @@ const jestExpectFailAssertHttpErrorServerErrorCode = expectFailAssertHttpErrorSe
|
|
|
1220
1154
|
* Host of localhost, port 9904
|
|
1221
1155
|
*/
|
|
1222
1156
|
const adminFirestoreFactory = googleCloudTestFirestoreBuilder({
|
|
1223
|
-
|
|
1224
|
-
|
|
1157
|
+
host: 'localhost',
|
|
1158
|
+
port: 9904
|
|
1225
1159
|
});
|
|
1226
1160
|
/**
|
|
1227
1161
|
* Convenience mock instance for tests within an authorized context.
|
|
@@ -1236,8 +1170,8 @@ const dbxComponentsAdminTestWithMockItemCollection = test$1.testWithMockItemColl
|
|
|
1236
1170
|
* Host of localhost, port 9906
|
|
1237
1171
|
*/
|
|
1238
1172
|
const adminFirebaseStorageFactory = googleCloudTestFirebaseStorageBuilder({
|
|
1239
|
-
|
|
1240
|
-
|
|
1173
|
+
host: '0.0.0.0',
|
|
1174
|
+
port: 9906
|
|
1241
1175
|
});
|
|
1242
1176
|
/**
|
|
1243
1177
|
* Convenience mock instance for tests within an authorized context.
|