diff --git a/firestore-bigquery-export/functions/__tests__/functions.test.ts b/firestore-bigquery-export/functions/__tests__/functions.test.ts index a96568767..4d1fc2c15 100644 --- a/firestore-bigquery-export/functions/__tests__/functions.test.ts +++ b/firestore-bigquery-export/functions/__tests__/functions.test.ts @@ -2,8 +2,8 @@ import * as admin from "firebase-admin"; import { logger } from "firebase-functions"; import * as functionsTestInit from "../node_modules/firebase-functions-test"; import mockedEnv from "../node_modules/mocked-env"; -import { mockConsoleLog } from "./__mocks__/console"; import config from "../src/config"; +import { mockConsoleLog } from "./__mocks__/console"; // Mock Firestore BigQuery Tracker jest.mock("@firebaseextensions/firestore-bigquery-change-tracker", () => ({ @@ -19,11 +19,10 @@ jest.mock("@firebaseextensions/firestore-bigquery-change-tracker", () => ({ })); // Mock firebase-admin eventarc +const channelMock = { publish: jest.fn() }; jest.mock("firebase-admin/eventarc", () => ({ getEventarc: jest.fn(() => ({ - channel: jest.fn(() => ({ - publish: jest.fn(), - })), + channel: jest.fn(() => channelMock), })), })); @@ -36,6 +35,9 @@ jest.mock("../src/logs", () => ({ complete: jest.fn(() => logger.log("Completed execution of extension")), })); +// Mock Console +console.info = jest.fn(); // Mock console.info globally + // Environment Variables const defaultEnvironment = { PROJECT_ID: "fake-project", @@ -47,7 +49,7 @@ const defaultEnvironment = { }; let restoreEnv; -let functionsTest = functionsTestInit(); +let functionsTest; /** Helper to Mock Export */ const mockExport = (document, data) => { @@ -60,11 +62,12 @@ describe("extension", () => { beforeEach(() => { restoreEnv = mockedEnv(defaultEnvironment); jest.resetModules(); + functionsTest = functionsTestInit(); + jest.clearAllMocks(); }); afterEach(() => { restoreEnv(); - jest.clearAllMocks(); }); test("functions are exported", () => { @@ -79,9 +82,9 @@ describe("extension", () => { functionsConfig = config; }); - test("function runs with a CREATE event and publishes both old and new events", async () => { + test("function runs with a CREATE event", async () => { const beforeSnapshot = functionsTest.firestore.makeDocumentSnapshot( - {}, // Empty data to simulate no document + {}, // Empty to simulate no document "example/doc1" ); const afterSnapshot = functionsTest.firestore.makeDocumentSnapshot( @@ -100,30 +103,17 @@ describe("extension", () => { expect(callResult).toBeUndefined(); - // Verify Logs expect(mockConsoleLog).toBeCalledWith( "Started execution of extension with configuration", - functionsConfig - ); - expect(mockConsoleLog).toBeCalledWith("Completed execution of extension"); - - // Verify Event Publishing - const eventarcMock = require("firebase-admin/eventarc").getEventarc; - const channelMock = eventarcMock().channel(); - - expect(channelMock.publish).toHaveBeenCalledTimes(2); - expect(channelMock.publish).toHaveBeenCalledWith( - expect.objectContaining({ - type: "firebase.extensions.firestore-counter.v1.onStart", - data: expect.any(Object), - }) - ); - expect(channelMock.publish).toHaveBeenCalledWith( expect.objectContaining({ - type: "firebase.extensions.firestore-bigquery-export.v1.onStart", - data: expect.any(Object), + backupBucketName: expect.any(String), + initialized: expect.any(Boolean), + maxDispatchesPerSecond: expect.any(Number), + maxEnqueueAttempts: expect.any(Number), }) ); + + expect(mockConsoleLog).toBeCalledWith("Completed execution of extension"); }); test("function runs with a DELETE event", async () => { @@ -132,7 +122,7 @@ describe("extension", () => { "example/doc1" ); const afterSnapshot = functionsTest.firestore.makeDocumentSnapshot( - {}, // Empty data to simulate no document + {}, // Empty to simulate document deletion "example/doc1" ); @@ -147,30 +137,17 @@ describe("extension", () => { expect(callResult).toBeUndefined(); - // Verify Logs expect(mockConsoleLog).toBeCalledWith( "Started execution of extension with configuration", - functionsConfig - ); - expect(mockConsoleLog).toBeCalledWith("Completed execution of extension"); - - // Verify Event Publishing for both old and new event types - const eventarcMock = require("firebase-admin/eventarc").getEventarc; - const channelMock = eventarcMock().channel(); - - expect(channelMock.publish).toHaveBeenCalledTimes(2); - expect(channelMock.publish).toHaveBeenCalledWith( expect.objectContaining({ - type: "firebase.extensions.firestore-counter.v1.onCompletion", - data: expect.any(Object), - }) - ); - expect(channelMock.publish).toHaveBeenCalledWith( - expect.objectContaining({ - type: "firebase.extensions.firestore-bigquery-export.v1.onCompletion", - data: expect.any(Object), + backupBucketName: expect.any(String), + initialized: expect.any(Boolean), + maxDispatchesPerSecond: expect.any(Number), + maxEnqueueAttempts: expect.any(Number), }) ); + + expect(mockConsoleLog).toBeCalledWith("Completed execution of extension"); }); }); }); diff --git a/firestore-bigquery-export/functions/src/events.ts b/firestore-bigquery-export/functions/src/events.ts index d7506dcea..aecc52857 100644 --- a/firestore-bigquery-export/functions/src/events.ts +++ b/firestore-bigquery-export/functions/src/events.ts @@ -49,7 +49,7 @@ export const setupEventChannel = () => { * @returns A Promise resolving when both events are published. */ export const recordStartEvent = async (data: string | object) => { - if (!eventChannel) return; + if (!eventChannel) return Promise.resolve(); // Explicitly return a resolved Promise const eventTypes = getEventTypes("onStart"); @@ -72,7 +72,7 @@ export const recordStartEvent = async (data: string | object) => { * @returns A Promise resolving when both events are published. */ export const recordErrorEvent = async (err: Error, subject?: string) => { - if (!eventChannel) return; + if (!eventChannel) return Promise.resolve(); // Ensure consistent return type const eventTypes = getEventTypes("onError"); @@ -103,7 +103,7 @@ export const recordSuccessEvent = async ({ subject: string; data: string | object; }) => { - if (!eventChannel) return; + if (!eventChannel) return Promise.resolve(); // Explicitly return a resolved Promise const eventTypes = getEventTypes("onSuccess"); @@ -126,7 +126,7 @@ export const recordSuccessEvent = async ({ * @returns A Promise resolving when both events are published. */ export const recordCompletionEvent = async (data: string | object) => { - if (!eventChannel) return; + if (!eventChannel) return Promise.resolve(); // Ensure consistent return type const eventTypes = getEventTypes("onCompletion");