From 4cc02f7959e20e1cbaceb283c5ceb7dce4e918ca Mon Sep 17 00:00:00 2001 From: Nathan Vasse Date: Wed, 29 Apr 2026 17:12:30 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20match=20event=20propertie?= =?UTF-8?q?s=20in=20posthog=20e2e=20helper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Asserting only on the event name is not enough when the same event is emitted from multiple call sites with different payloads. Expose expectEventSentWithProps so specs can pin down the expected slot or context, and keep the captured properties available alongside the existing names array. --- .../app-drive/utils/posthog-utils.ts | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/src/frontend/apps/e2e/__tests__/app-drive/utils/posthog-utils.ts b/src/frontend/apps/e2e/__tests__/app-drive/utils/posthog-utils.ts index f975bb66..397256b4 100644 --- a/src/frontend/apps/e2e/__tests__/app-drive/utils/posthog-utils.ts +++ b/src/frontend/apps/e2e/__tests__/app-drive/utils/posthog-utils.ts @@ -2,6 +2,11 @@ import { expect, Page } from "@playwright/test"; const FAKE_POSTHOG_HOST = "http://fake-ph.test"; +type CapturedEvent = { + event: string; + properties: Record; +}; + /** * Intercepts the config API to enable PostHog with a fake key and * captures all PostHog events sent by the page. @@ -9,12 +14,14 @@ const FAKE_POSTHOG_HOST = "http://fake-ph.test"; * Must be called **before** any page navigation (e.g. before `page.goto`). * * @returns An object with: - * - `events`: the live array of captured event names - * - `expectEventSent(name, timeout?)`: assertion helper that polls - * until the given event appears + * - `events`: the live array of captured events with their properties + * - `expectEventSent(name, timeout?)`: polls until the given event name appears + * - `expectEventSentWithProps(name, props, timeout?)`: polls until at least + * one captured event matches the name AND has every entry in `props` + * as a strict equality match */ export const setupPosthogEventCapture = async (page: Page) => { - const events: string[] = []; + const events: CapturedEvent[] = []; await page.route("**/api/v1.0/config/**", async (route) => { const response = await route.fetch(); @@ -28,7 +35,10 @@ export const setupPosthogEventCapture = async (page: Page) => { try { const postData = JSON.parse(route.request().postData() ?? "{}"); if (postData.event) { - events.push(postData.event); + events.push({ + event: postData.event, + properties: postData.properties ?? {}, + }); } } catch { // ignore non-JSON requests (e.g. /decide) @@ -42,9 +52,29 @@ export const setupPosthogEventCapture = async (page: Page) => { const expectEventSent = async (eventName: string, timeout = 5000) => { await expect - .poll(() => events.includes(eventName), { timeout }) + .poll(() => events.some((e) => e.event === eventName), { timeout }) .toBe(true); }; - return { events, expectEventSent }; + const expectEventSentWithProps = async ( + eventName: string, + expectedProps: Record, + timeout = 5000, + ) => { + await expect + .poll( + () => + events.some( + (e) => + e.event === eventName && + Object.entries(expectedProps).every( + ([k, v]) => e.properties[k] === v, + ), + ), + { timeout }, + ) + .toBe(true); + }; + + return { events, expectEventSent, expectEventSentWithProps }; };