diff --git a/frontend/tests/components/search/SearchAnalytics.test.tsx b/frontend/tests/components/search/SearchAnalytics.test.tsx index 134bf4806..9a472a424 100644 --- a/frontend/tests/components/search/SearchAnalytics.test.tsx +++ b/frontend/tests/components/search/SearchAnalytics.test.tsx @@ -3,24 +3,37 @@ import { render } from "@testing-library/react"; import SearchAnalytics from "src/components/search/SearchAnalytics"; const sendGAEventMock = jest.fn(); +const waitForNewRelicMock = jest.fn(); +const setNewRelicCustomAttributeMock = jest.fn(); +const unsetAllNewRelicQueryAttributesMock = jest.fn(); jest.mock("@next/third-parties/google", () => ({ /* eslint-disable-next-line @typescript-eslint/no-unsafe-return */ sendGAEvent: (...args: unknown[]) => sendGAEventMock(...args), })); +jest.mock("src/utils/analyticsUtil", () => ({ + waitForNewRelic: () => waitForNewRelicMock(), + setNewRelicCustomAttribute: (...args) => + setNewRelicCustomAttributeMock(...args), + unsetAllNewRelicQueryAttributes: () => unsetAllNewRelicQueryAttributesMock(), +})); + +const basicParams = { + fundingInstrument: "cooperative_agreement", + status: "posted, archived", + agency: "AC,PAMS-SC", + page: "1", + query: "a random search term", +}; + describe("SearchAnalytics", () => { + afterEach(() => { + jest.resetAllMocks(); + }); it("calls sendGAEvent with expected params on render", () => { const { rerender } = render( - , + , ); expect(sendGAEventMock).toHaveBeenCalledWith("event", "search_attempt", { search_filters: @@ -36,6 +49,7 @@ describe("SearchAnalytics", () => { page: "1", query: "a random search term", }} + newRelicEnabled={false} />, ); expect(sendGAEventMock).toHaveBeenCalledWith("event", "search_attempt", { @@ -43,4 +57,85 @@ describe("SearchAnalytics", () => { '{"status":"posted, archived, closed","agency":"AC","category":"recovery_act"}', }); }); + + it("does not waitForNewRelic if New Relic is not enabled", () => { + render(); + expect(waitForNewRelicMock).not.toHaveBeenCalled(); + }); + + it("does not attempt to set custom attributes if New Relic is not enabled", () => { + const { rerender } = render( + , + ); + + rerender( + , + ); + expect(setNewRelicCustomAttributeMock).not.toHaveBeenCalled(); + }); + + it("does not attempt to set custom attributes if New Relic is not initialized", () => { + waitForNewRelicMock.mockResolvedValue(false); + const { rerender } = render( + , + ); + + rerender( + , + ); + expect(setNewRelicCustomAttributeMock).not.toHaveBeenCalled(); + }); + + it("calls setNewRelicCustomAttribute for all search params when params change", async () => { + waitForNewRelicMock.mockImplementation(() => { + return Promise.resolve(true); + }); + const { rerender } = render( + , + ); + + // have to wait a tick for the wait promise to resolve + const animationFramePromise = new Promise((resolve) => { + requestAnimationFrame(resolve); + }); + + await animationFramePromise; + + rerender( + , + ); + Object.entries({ + ...basicParams, + page: "2", + }).forEach(([key, value]) => { + expect(setNewRelicCustomAttributeMock).toHaveBeenCalledWith(key, value); + }); + }); + + it("calls unsetAllNewRelicQueryAttributes on cleanup", () => { + waitForNewRelicMock.mockImplementation(() => { + return Promise.resolve(true); + }); + render(); + + expect(unsetAllNewRelicQueryAttributesMock).toHaveBeenCalled(); + }); });