Skip to content

Commit d3aad4a

Browse files
committed
Fix tests.
1 parent 400a13c commit d3aad4a

File tree

4 files changed

+21
-66
lines changed

4 files changed

+21
-66
lines changed

functions/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"deploy": "firebase deploy --only functions",
1111
"logs": "firebase functions:log",
1212
"test": "npm run test:unit && npm run test:firestore",
13-
"test:firestore": "firebase -c firebase-test.json emulators:exec --only firestore,functions --project=demo-deliberate-lab \"npx jest $npm_package_config_firestore_tests\"",
13+
"test:firestore": "firebase -c firebase-test.json emulators:exec --only firestore,functions --project=demo-deliberate-lab \"npx jest --runInBand $npm_package_config_firestore_tests\"",
1414
"test:unit": "npx jest --testPathIgnorePatterns=$npm_package_config_firestore_tests",
1515
"typecheck": "tsc --noEmit"
1616
},

functions/src/dl_api/dl_api_key.utils.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
* Handles generation, hashing, storage, and verification of API keys
44
*/
55

6-
import * as admin from 'firebase-admin';
76
import {randomBytes, scrypt, createHash, timingSafeEqual} from 'crypto';
87
import {promisify} from 'util';
98
import {
109
DeliberateLabAPIKeyPermission,
1110
DeliberateLabAPIKeyData,
1211
} from '@deliberation-lab/utils';
12+
import {app} from '../app';
1313

1414
const scryptAsync = promisify(scrypt);
1515

@@ -67,7 +67,6 @@ export async function createDeliberateLabAPIKey(
6767
DeliberateLabAPIKeyPermission.WRITE,
6868
],
6969
): Promise<{apiKey: string; keyId: string}> {
70-
const app = admin.app();
7170
const firestore = app.firestore();
7271

7372
// Generate the API key
@@ -104,7 +103,6 @@ export async function createDeliberateLabAPIKey(
104103
export async function verifyDeliberateLabAPIKey(
105104
apiKey: string,
106105
): Promise<{valid: boolean; data?: DeliberateLabAPIKeyData}> {
107-
const app = admin.app();
108106
const firestore = app.firestore();
109107

110108
// Get key ID to look up the document
@@ -151,7 +149,6 @@ export async function revokeDeliberateLabAPIKey(
151149
keyId: string,
152150
experimenterId: string,
153151
): Promise<boolean> {
154-
const app = admin.app();
155152
const firestore = app.firestore();
156153

157154
const doc = await firestore
@@ -195,7 +192,6 @@ export async function listDeliberateLabAPIKeys(experimenterId: string): Promise<
195192
permissions: DeliberateLabAPIKeyPermission[];
196193
}>
197194
> {
198-
const app = admin.app();
199195
const firestore = app.firestore();
200196

201197
const snapshot = await firestore

functions/src/dl_api/experiments.dl_api.integration.test.ts

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,14 @@
44
* These tests verify that experiments created via the REST API are equivalent
55
* to experiments created using the traditional template system.
66
*
7-
* This test assumes that a Firestore emulator is running.
8-
* Run using: npm run test:firestore experiments.api.integration.test.ts
9-
* Or: firebase emulators:exec --only firestore "npx jest experiments.api.integration.test.ts"
7+
* This test requires a Firestore emulator running. Run via:
8+
* npm run test:firestore
109
*/
1110

12-
// Don't override GCLOUD_PROJECT - let firebase emulators:exec set it
13-
// If not set, use a demo project ID that the emulator will accept
14-
if (!process.env.GCLOUD_PROJECT) {
15-
process.env.GCLOUD_PROJECT = 'demo-deliberate-lab';
16-
}
17-
1811
import {
1912
initializeTestEnvironment,
2013
RulesTestEnvironment,
2114
} from '@firebase/rules-unit-testing';
22-
import * as admin from 'firebase-admin';
2315
import {
2416
createExperimentConfig,
2517
StageConfig,
@@ -53,8 +45,7 @@ describe('API Experiment Creation Integration Tests', () => {
5345
const createdExperimentIds: string[] = [];
5446

5547
beforeAll(async () => {
56-
// Use the same project ID that the emulator will use
57-
const projectId = process.env.GCLOUD_PROJECT || 'demo-deliberate-lab';
48+
const projectId = 'demo-deliberate-lab';
5849

5950
testEnv = await initializeTestEnvironment({
6051
projectId,
@@ -68,13 +59,6 @@ describe('API Experiment Creation Integration Tests', () => {
6859
firestore = testEnv.unauthenticatedContext().firestore();
6960
firestore.settings({ignoreUndefinedProperties: true, merge: true});
7061

71-
// Initialize Firebase Admin SDK (will use emulator via FIRESTORE_EMULATOR_HOST environment variable)
72-
if (!admin.apps.length) {
73-
admin.initializeApp({
74-
projectId,
75-
});
76-
}
77-
7862
// Create test API key (this will be stored in the emulator)
7963
console.log('Creating API key...');
8064
const {apiKey} = await createDeliberateLabAPIKey(
@@ -99,7 +83,7 @@ describe('API Experiment Creation Integration Tests', () => {
9983
process.env.FIREBASE_FUNCTIONS_EMULATOR_PORT || '5001';
10084
const region = 'us-central1'; // Default region for Cloud Functions
10185

102-
baseUrl = `http://${functionsHost}:${functionsPort}/${projectId}/${region}/api`;
86+
baseUrl = `http://${functionsHost}:${functionsPort}/{$projectId}/${region}/api`;
10387
console.log('API base URL:', baseUrl);
10488
});
10589

functions/src/variables.utils.test.ts

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
// This test requires a Firestore emulator running. Run via:
22
// npm run test:firestore
3-
// Or manually:
4-
// FIRESTORE_EMULATOR_HOST="localhost:8080" npx jest src/variables.utils.test.ts
53

6-
// Set project ID before importing firebase-admin
7-
if (!process.env.GCLOUD_PROJECT) {
8-
process.env.GCLOUD_PROJECT = 'demo-deliberate-lab';
9-
}
10-
11-
import * as admin from 'firebase-admin';
4+
import {app} from './app';
125
import {
136
initializeTestEnvironment,
147
RulesTestEnvironment,
@@ -27,23 +20,15 @@ import {
2720
} from '@deliberation-lab/utils';
2821
import {generateVariablesForScope} from './variables.utils';
2922

30-
let mockFirestore: FirebaseFirestore.Firestore;
31-
32-
jest.mock('./app', () => ({
33-
app: {
34-
firestore: () => mockFirestore,
35-
},
36-
}));
23+
const firestore = app.firestore();
3724

3825
describe('generateVariablesForScope', () => {
3926
let testEnv: RulesTestEnvironment;
4027

4128
beforeAll(async () => {
42-
const projectId = process.env.GCLOUD_PROJECT || 'demo-deliberate-lab';
43-
4429
// Initialize test environment for cleanup utilities
4530
testEnv = await initializeTestEnvironment({
46-
projectId,
31+
projectId: 'demo-deliberate-lab',
4732
firestore: process.env.FIRESTORE_EMULATOR_HOST
4833
? undefined
4934
: {
@@ -52,24 +37,14 @@ describe('generateVariablesForScope', () => {
5237
},
5338
});
5439

55-
// Initialize Firebase Admin SDK - this connects to the emulator
56-
// via FIRESTORE_EMULATOR_HOST environment variable and has full
57-
// Firestore API support including .count()
58-
if (!admin.apps.length) {
59-
admin.initializeApp({projectId});
60-
}
61-
mockFirestore = admin.firestore();
62-
mockFirestore.settings({ignoreUndefinedProperties: true});
40+
// Clear any leftover data from previous test runs
41+
await testEnv.clearFirestore();
6342
});
6443

6544
afterAll(async () => {
6645
await testEnv.cleanup();
6746
});
6847

69-
beforeEach(async () => {
70-
await testEnv.clearFirestore();
71-
});
72-
7348
describe('static variables', () => {
7449
it('should generate static variables for matching scope', async () => {
7550
const config = createStaticVariableConfig({
@@ -167,7 +142,7 @@ describe('generateVariablesForScope', () => {
167142
expect(result1['condition']).toBe(JSON.stringify('control'));
168143

169144
// Add a participant to Firestore
170-
await mockFirestore
145+
await firestore
171146
.collection(`experiments/${experimentId}/participants`)
172147
.doc('p1')
173148
.set(
@@ -189,7 +164,7 @@ describe('generateVariablesForScope', () => {
189164
expect(result2['condition']).toBe(JSON.stringify('treatment'));
190165

191166
// Add second participant
192-
await mockFirestore
167+
await firestore
193168
.collection(`experiments/${experimentId}/participants`)
194169
.doc('p2')
195170
.set(
@@ -225,7 +200,7 @@ describe('generateVariablesForScope', () => {
225200

226201
// Add participants with existing assignments
227202
// 2 in group A, 1 in group B, 0 in group C
228-
await mockFirestore
203+
await firestore
229204
.collection(`experiments/${experimentId}/participants`)
230205
.doc('existing1')
231206
.set({
@@ -238,7 +213,7 @@ describe('generateVariablesForScope', () => {
238213
variableMap: {group: JSON.stringify('A')},
239214
});
240215

241-
await mockFirestore
216+
await firestore
242217
.collection(`experiments/${experimentId}/participants`)
243218
.doc('existing2')
244219
.set({
@@ -251,7 +226,7 @@ describe('generateVariablesForScope', () => {
251226
variableMap: {group: JSON.stringify('A')},
252227
});
253228

254-
await mockFirestore
229+
await firestore
255230
.collection(`experiments/${experimentId}/participants`)
256231
.doc('existing3')
257232
.set({
@@ -328,7 +303,7 @@ describe('generateVariablesForScope', () => {
328303
const cohortB = 'cohort-B';
329304

330305
// Add 1 participant to cohort A
331-
await mockFirestore
306+
await firestore
332307
.collection(`experiments/${experimentId}/participants`)
333308
.doc('pA1')
334309
.set(
@@ -410,7 +385,7 @@ describe('generateVariablesForScope', () => {
410385
expect(result0['weighted_condition']).toBe(JSON.stringify('A'));
411386

412387
// Add participant 0
413-
await mockFirestore
388+
await firestore
414389
.collection(`experiments/${expId}/participants`)
415390
.doc('wp0')
416391
.set(
@@ -432,7 +407,7 @@ describe('generateVariablesForScope', () => {
432407
expect(result1['weighted_condition']).toBe(JSON.stringify('A'));
433408

434409
// Add participant 1
435-
await mockFirestore
410+
await firestore
436411
.collection(`experiments/${expId}/participants`)
437412
.doc('wp1')
438413
.set(
@@ -472,7 +447,7 @@ describe('generateVariablesForScope', () => {
472447

473448
// Add 1 participant to each group (50/50 split)
474449
// Target is 67/33, so A is under-represented
475-
await mockFirestore
450+
await firestore
476451
.collection(`experiments/${expId}/participants`)
477452
.doc('existing1')
478453
.set({
@@ -485,7 +460,7 @@ describe('generateVariablesForScope', () => {
485460
variableMap: {weighted_group: JSON.stringify('A')},
486461
});
487462

488-
await mockFirestore
463+
await firestore
489464
.collection(`experiments/${expId}/participants`)
490465
.doc('existing2')
491466
.set({

0 commit comments

Comments
 (0)