Skip to content

Commit 4c44b6e

Browse files
committed
add auth,database tests
1 parent 6006808 commit 4c44b6e

22 files changed

+2491
-158
lines changed

integration_test/functions/package-lock.json

Lines changed: 1516 additions & 43 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integration_test/functions/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"main": "lib/index.js",
1616
"dependencies": {
1717
"@google-cloud/pubsub": "^5.2.0",
18+
"firebase": "^12.6.0",
1819
"firebase-admin": "^12.6.0",
1920
"firebase-functions": "file:firebase-functions-local.tgz"
2021
},

integration_test/functions/src/assertions.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { expect, assertType } from "vitest";
2+
3+
export * from "./index";
4+
5+
export function expectAuthBlockingEvent(data: any, userId: string) {
6+
// expect(data.auth).toBeDefined(); // TOOD: Not provided?
7+
expect(data.authType).toBeDefined();
8+
assertType<string>(data.authType);
9+
expect(data.eventId).toBeDefined();
10+
assertType<string>(data.eventId);
11+
expect(data.eventType).toBeDefined();
12+
assertType<string>(data.eventType);
13+
expect(data.timestamp).toBeDefined();
14+
assertType<string>(data.timestamp);
15+
expect(Date.parse(data.timestamp)).toBeGreaterThan(0);
16+
17+
expect(data.locale).toBeDefined();
18+
expect(data.ipAddress).toBeDefined();
19+
assertType<string>(data.ipAddress);
20+
expect(data.ipAddress.length).toBeGreaterThan(0);
21+
expect(data.userAgent).toBeDefined();
22+
assertType<string>(data.userAgent);
23+
expect(data.userAgent.length).toBeGreaterThan(0);
24+
25+
expect(data.additionalUserInfo).toBeDefined();
26+
expect(data.additionalUserInfo.isNewUser).toBe(true);
27+
expect(data.additionalUserInfo.providerId).toBe("password");
28+
29+
// TODO: data.credential is null
30+
31+
expect(data.data).toBeDefined();
32+
expect(data.data.uid).toBe(userId);
33+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { expect, assertType } from "vitest";
2+
import { RUN_ID } from "../utils";
3+
4+
export * from "./index";
5+
6+
export function expectDatabaseEvent(data: any, eventName: string, refPath: string) {
7+
expect(data.location).toBeDefined();
8+
assertType<string>(data.location);
9+
expect(data.location.length).toBeGreaterThan(0);
10+
expect(data.firebaseDatabaseHost).toBeDefined();
11+
assertType<string>(data.firebaseDatabaseHost);
12+
expect(data.firebaseDatabaseHost.length).toBeGreaterThan(0);
13+
expect(data.instance).toBeDefined();
14+
assertType<string>(data.instance);
15+
expect(data.instance.length).toBeGreaterThan(0);
16+
expect(data.ref).toBeDefined();
17+
assertType<string>(data.ref);
18+
expect(data.ref).toBe(refPath);
19+
expect(data.params).toBeDefined();
20+
expect(data.params.runId).toBe(RUN_ID);
21+
}
22+
23+
export function expectDataSnapshot(snapshot: any, refPath: string) {
24+
expect(snapshot.ref).toBeDefined();
25+
expect(snapshot.ref.__type).toBe("reference");
26+
expect(snapshot.ref.key).toBeDefined();
27+
expect(snapshot.key).toBeDefined();
28+
expect(snapshot.exists).toBe(true);
29+
expect(snapshot.hasChildren).toBeDefined();
30+
expect(typeof snapshot.hasChildren).toBe("boolean");
31+
expect(snapshot.hasChild).toBeDefined();
32+
expect(typeof snapshot.hasChild).toBe("boolean");
33+
expect(snapshot.numChildren).toBeDefined();
34+
expect(typeof snapshot.numChildren).toBe("number");
35+
expect(snapshot.json).toBeDefined();
36+
expect(typeof snapshot.json).toBe("object");
37+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { expect, assertType } from "vitest";
2+
import { RUN_ID } from "../utils";
3+
4+
export * from "./index";
5+
6+
export function expectFirestoreAuthEvent(data: any, collection: string, document: string) {
7+
expect(data.authId).toBeDefined();
8+
assertType<string>(data.authId);
9+
expect(data.authId.length).toBeGreaterThan(0);
10+
expect(data.authType).toBeDefined();
11+
assertType<string>(data.authType);
12+
expect(data.authType.length).toBeGreaterThan(0);
13+
expectFirestoreEvent(data, collection, document);
14+
}
15+
16+
export function expectFirestoreEvent(data: any, collection: string, document: string) {
17+
expect(data.location).toBeDefined();
18+
assertType<string>(data.location);
19+
expect(data.location.length).toBeGreaterThan(0);
20+
expect(data.project).toBeDefined();
21+
assertType<string>(data.project);
22+
expect(data.project.length).toBeGreaterThan(0);
23+
expect(data.database).toBeDefined();
24+
assertType<string>(data.database);
25+
expect(data.database.length).toBeGreaterThan(0);
26+
expect(data.namespace).toBeDefined();
27+
assertType<string>(data.namespace);
28+
expect(data.namespace.length).toBeGreaterThan(0);
29+
expect(data.document).toBeDefined();
30+
assertType<string>(data.document);
31+
expect(data.document.length).toBeGreaterThan(0);
32+
expect(data.document).toBe(`integration_test/${RUN_ID}/${collection}/${document}`);
33+
expect(data.params).toBeDefined();
34+
expect(data.params.runId).toBe(RUN_ID);
35+
expect(data.params.documentId).toBe(document);
36+
}
37+
38+
export function expectQueryDocumentSnapshot(snapshot: any, collection: string, document: string) {
39+
expect(snapshot.exists).toBe(true);
40+
expect(snapshot.id).toBe(document);
41+
expectDocumentReference(snapshot.ref, collection, document);
42+
expectTimestamp(snapshot.createTime);
43+
expectTimestamp(snapshot.updateTime);
44+
}
45+
46+
export function expectDocumentReference(reference: any, collection: string, document: string) {
47+
expect(reference._type).toBe("reference");
48+
expect(reference.id).toBe(document);
49+
expect(reference.path).toBe(`integration_test/${RUN_ID}/${collection}/${document}`);
50+
}
51+
52+
export function expectTimestamp(timestamp: any) {
53+
expect(timestamp._type).toBe("timestamp");
54+
expect(Date.parse(timestamp.iso)).toBeGreaterThan(0);
55+
expect(Number(timestamp.seconds)).toBeGreaterThan(0);
56+
expect(Number(timestamp.nanoseconds)).toBeGreaterThan(0);
57+
}
58+
59+
export function expectGeoPoint(geoPoint: any) {
60+
expect(geoPoint._type).toBe("geopoint");
61+
expect(Number(geoPoint.latitude)).toBeGreaterThan(0);
62+
expect(Number(geoPoint.longitude)).toBeGreaterThan(0);
63+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { expect, assertType } from "vitest";
2+
3+
export function expectCloudEvent(data: any) {
4+
expect(data.specversion).toBe("1.0");
5+
expect(data.id).toBeDefined();
6+
assertType<string>(data.id);
7+
expect(data.id.length).toBeGreaterThan(0);
8+
expect(data.source).toBeDefined();
9+
assertType<string>(data.source);
10+
expect(data.source.length).toBeGreaterThan(0);
11+
expect(data.subject).toBeDefined();
12+
assertType<string>(data.subject);
13+
expect(data.subject.length).toBeGreaterThan(0);
14+
expect(data.type).toBeDefined();
15+
assertType<string>(data.type);
16+
expect(data.type.length).toBeGreaterThan(0);
17+
expect(data.time).toBeDefined();
18+
assertType<string>(data.time);
19+
expect(data.time.length).toBeGreaterThan(0);
20+
// iso string to unix - will be NaN if not a valid date
21+
expect(Date.parse(data.time)).toBeGreaterThan(0);
22+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { describe, it, beforeAll, afterAll, expect } from "vitest";
2+
import { createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut } from "firebase/auth";
3+
import { auth, waitForEvent } from "./utils";
4+
import { expectAuthBlockingEvent } from "./assertions/auth";
5+
import { auth as authClient } from "./client";
6+
7+
describe("auth.v2", () => {
8+
describe("beforeUserCreated", () => {
9+
let data: any;
10+
let userId: string;
11+
let email: string;
12+
13+
beforeAll(async () => {
14+
data = await waitForEvent("beforeUserCreated", async () => {
15+
email = `test-${Date.now()}@example.com`;
16+
const password = "testPassword123!";
17+
userId = await createUserWithEmailAndPassword(authClient, email, password).then(
18+
(credential) => credential.user.uid
19+
);
20+
});
21+
}, 60_000);
22+
23+
afterAll(async () => {
24+
// Clean up: delete the test user
25+
if (userId) {
26+
try {
27+
await auth.deleteUser(userId);
28+
} catch (error) {
29+
// Ignore errors if user was already deleted
30+
}
31+
}
32+
33+
await signOut(authClient);
34+
});
35+
36+
it("should be an AuthBlockingEvent", () => {
37+
expectAuthBlockingEvent(data, userId);
38+
});
39+
40+
it("should have the correct event type", () => {
41+
expect(data.eventType).toBe("providers/cloud.auth/eventTypes/user.beforeCreate:password");
42+
});
43+
});
44+
45+
describe("beforeUserSignedIn", () => {
46+
let data: any;
47+
let userId: string;
48+
let email: string;
49+
let password: string;
50+
51+
beforeAll(async () => {
52+
// First create a user via REST API
53+
email = `signin-${Date.now()}@example.com`;
54+
password = "testPassword123!";
55+
userId = await createUserWithEmailAndPassword(authClient, email, password).then(
56+
(credential) => credential.user.uid
57+
);
58+
59+
await new Promise((resolve) => setTimeout(resolve, 2000));
60+
61+
data = await waitForEvent("beforeUserSignedIn", async () => {
62+
await signInWithEmailAndPassword(authClient, email, password);
63+
});
64+
}, 60_000);
65+
66+
afterAll(async () => {
67+
// Clean up: delete the test user
68+
if (userId) {
69+
try {
70+
await auth.deleteUser(userId);
71+
} catch (error) {
72+
// Ignore errors if user was already deleted
73+
}
74+
}
75+
76+
await signOut(authClient);
77+
});
78+
79+
it("should be an AuthBlockingEvent", () => {
80+
expectAuthBlockingEvent(data, userId);
81+
});
82+
83+
it("should have the correct event type", () => {
84+
expect(data.eventType).toBe("providers/cloud.auth/eventTypes/user.beforeSignIn:password");
85+
});
86+
});
87+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { beforeUserCreated, beforeUserSignedIn } from "firebase-functions/v2/identity";
2+
import { sendEvent } from "./utils";
3+
import { serializeAuthBlockingEvent } from "./serializers/auth";
4+
5+
export const authBeforeUserCreatedTrigger = beforeUserCreated(async (event) => {
6+
await sendEvent("beforeUserCreated", serializeAuthBlockingEvent(event));
7+
});
8+
9+
export const authBeforeUserSignedInTrigger = beforeUserSignedIn(async (event) => {
10+
await sendEvent("beforeUserSignedIn", serializeAuthBlockingEvent(event));
11+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { initializeApp } from "firebase/app";
2+
import { getAuth } from "firebase/auth";
3+
4+
export const app = initializeApp({
5+
apiKey: "AIzaSyBBt77mpu6TV0IA2tcNSyf4OltsVu_Z1Zw",
6+
authDomain: "cf3-integration-tests-v2-qa.firebaseapp.com",
7+
databaseURL: "https://cf3-integration-tests-v2-qa-default-rtdb.firebaseio.com",
8+
projectId: "cf3-integration-tests-v2-qa",
9+
storageBucket: "cf3-integration-tests-v2-qa.firebasestorage.app",
10+
messagingSenderId: "576826020291",
11+
appId: "1:576826020291:web:488d568c5d4109df12ed76",
12+
});
13+
14+
export const auth = getAuth(app);

0 commit comments

Comments
 (0)