From fd28e6d7f32f666e052360eaf5be82bba843826c Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Sun, 1 Mar 2026 16:12:06 +0100 Subject: [PATCH 1/7] =?UTF-8?q?=E2=9C=A8=20feat(e2e):=20add=20Lightpanda?= =?UTF-8?q?=20Docker=20services=20to=20docker-compose?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `lightpanda` service (nightly image, CDP on :9222, healthcheck) and `run-e2e-tests-lightpanda` service under the `e2e-lightpanda` profile so the full Lightpanda-backed E2E stack can be launched with a single `docker compose --profile e2e-lightpanda up`. Co-Authored-By: Claude --- docker-compose.yml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index dbaaec054..8131cf37d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -309,6 +309,20 @@ services: run-migrations: condition: service_completed_successfully + lightpanda: + profiles: + - e2e-lightpanda + image: lightpanda/browser:nightly + container_name: ${COMPOSE_PROJECT_NAME:-dev}-lightpanda + environment: + LIGHTPANDA_DISABLE_TELEMETRY: 'true' + healthcheck: + test: + ['CMD-SHELL', 'wget -qO- http://127.0.0.1:9222/json/version || exit 1'] + interval: 2s + timeout: 2s + retries: 15 + run-e2e-tests: image: mcr.microsoft.com/playwright:v1.56.1-jammy container_name: ${COMPOSE_PROJECT_NAME:-dev}-run-e2e-tests-${PACKMIND_EDITION:-oss} @@ -334,6 +348,31 @@ services: backend: condition: service_healthy + run-e2e-tests-lightpanda: + image: mcr.microsoft.com/playwright:v1.56.1-jammy + container_name: ${COMPOSE_PROJECT_NAME:-dev}-run-e2e-tests-lightpanda-${PACKMIND_EDITION:-oss} + profiles: + - e2e-lightpanda + volumes: + - .:/packmind + - dev-node_modules:/packmind/node_modules + - dev-dist:/packmind/dist + - dev-tmp:/packmind/tmp + - dev-nx-sock:/nx-sock + working_dir: /packmind/apps/e2e-tests + entrypoint: npm run e2e:lightpanda + environment: + BASE_URL: http://frontend:4200 + CI: 'true' + LIGHTPANDA_WS_ENDPOINT: ws://lightpanda:9222 + depends_on: + lightpanda: + condition: service_healthy + frontend: + condition: service_healthy + backend: + condition: service_healthy + volumes: dev-nx-sock: dev-postgres-data: From 39b2dcacfdf0acc41f210e137790f15a6c847993 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Sun, 1 Mar 2026 16:12:44 +0100 Subject: [PATCH 2/7] =?UTF-8?q?=E2=9C=A8=20feat(e2e):=20add=20Lightpanda?= =?UTF-8?q?=20Playwright=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add playwright.lightpanda.config.ts with video and screenshot disabled since Lightpanda has no rendering engine. Uses a single 'lightpanda' project and preserves trace on first retry. Co-Authored-By: Claude --- .../e2e-tests/playwright.lightpanda.config.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 apps/e2e-tests/playwright.lightpanda.config.ts diff --git a/apps/e2e-tests/playwright.lightpanda.config.ts b/apps/e2e-tests/playwright.lightpanda.config.ts new file mode 100644 index 000000000..5901144f6 --- /dev/null +++ b/apps/e2e-tests/playwright.lightpanda.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from '@playwright/test'; +import { nxE2EPreset } from '@nx/playwright/preset'; + +const baseURL = process.env['BASE_URL'] || 'http://localhost:4200'; +const isCI = !!process.env.CI; + +export default defineConfig({ + ...nxE2EPreset(__filename, { testDir: './src' }), + reporter: [['html', { open: isCI ? 'never' : 'on-failure' }]], + use: { + baseURL, + trace: 'on-first-retry', + // video and screenshot disabled — Lightpanda has no rendering engine + video: 'off', + screenshot: 'off', + }, + projects: [ + { + name: 'lightpanda', + }, + ], +}); From 172405bd14c9611a1370dd9809c474f894bf996a Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Sun, 1 Mar 2026 16:13:40 +0100 Subject: [PATCH 3/7] =?UTF-8?q?=E2=9C=A8=20feat(e2e):=20override=20browser?= =?UTF-8?q?=20fixture=20to=20support=20Lightpanda=20via=20CDP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When LIGHTPANDA_WS_ENDPOINT is set, connect to the Lightpanda browser over CDP using chromium.connectOverCDP() instead of launching a local Chromium instance. All downstream fixtures (testWithUserSignedUp, testWithApi) inherit this automatically via the fixture chain. Co-Authored-By: Claude --- apps/e2e-tests/src/fixtures/packmindTest.ts | 26 +++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/e2e-tests/src/fixtures/packmindTest.ts b/apps/e2e-tests/src/fixtures/packmindTest.ts index 43a4a174b..51da898dd 100644 --- a/apps/e2e-tests/src/fixtures/packmindTest.ts +++ b/apps/e2e-tests/src/fixtures/packmindTest.ts @@ -1,4 +1,5 @@ -import { test as base } from '@playwright/test'; +import { test as base, Browser } from '@playwright/test'; +import { chromium } from 'playwright-core'; import { v4 as uuidv4 } from 'uuid'; import { IPackmindApi } from '../domain/api/IPackmindApi'; import { PackmindApi } from '../infra/api/PackmindApi'; @@ -6,7 +7,28 @@ import { SignUpWithOrganizationCommand } from '@packmind/types'; import { IDashboardPage, IPageFactory } from '../domain/pages'; import { PageFactory } from '../infra/PageFactory'; -export const testWithUserData = base.extend<{ +// Override the built-in browser fixture to support Lightpanda via CDP +const testBase = base.extend, { browser: Browser }>({ + browser: [ + async (_fixtures, use) => { + const wsEndpoint = process.env['LIGHTPANDA_WS_ENDPOINT']; + if (wsEndpoint) { + const browser = await chromium.connectOverCDP({ + endpointURL: wsEndpoint, + }); + await use(browser as unknown as Browser); + await browser.disconnect(); + } else { + const browser = await chromium.launch(); + await use(browser); + await browser.close(); + } + }, + { scope: 'worker' }, + ], +}); + +export const testWithUserData = testBase.extend<{ userData: SignUpWithOrganizationCommand; }>({ // eslint-disable-next-line no-empty-pattern From 6da5539cf0b8e6ecef212e81e03d6b90b8a01d26 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Sun, 1 Mar 2026 16:13:52 +0100 Subject: [PATCH 4/7] =?UTF-8?q?=E2=9C=A8=20feat(e2e):=20add=20e2e:lightpan?= =?UTF-8?q?da=20npm=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a dedicated script that runs Playwright with the Lightpanda-specific config (no video/screenshot, CDP-connected browser). Co-Authored-By: Claude --- apps/e2e-tests/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/e2e-tests/package.json b/apps/e2e-tests/package.json index dc3f112ea..5aba7aba8 100644 --- a/apps/e2e-tests/package.json +++ b/apps/e2e-tests/package.json @@ -3,6 +3,7 @@ "version": "0.0.1", "private": true, "scripts": { - "e2e": "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=false npx playwright test" + "e2e": "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=false npx playwright test", + "e2e:lightpanda": "playwright test --config=playwright.lightpanda.config.ts" } } From 78027cf0aa24ace0a02dff55920a286582547568 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Mon, 2 Mar 2026 10:24:28 +0100 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=90=9B=20fix(e2e):=20use=20bash=20/de?= =?UTF-8?q?v/tcp=20for=20Lightpanda=20healthcheck?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Lightpanda image does not ship wget or curl. Replace the healthcheck with a bash built-in TCP connection test which has no external dependencies. Co-Authored-By: Claude --- docker-compose.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8131cf37d..0af355991 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -317,8 +317,7 @@ services: environment: LIGHTPANDA_DISABLE_TELEMETRY: 'true' healthcheck: - test: - ['CMD-SHELL', 'wget -qO- http://127.0.0.1:9222/json/version || exit 1'] + test: ['CMD', 'bash', '-c', ' Date: Mon, 2 Mar 2026 10:28:59 +0100 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=90=9B=20fix(e2e):=20set=20locale:''?= =?UTF-8?q?=20to=20avoid=20Emulation.setUserAgentOverride?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Playwright's built-in locale fixture defaults to "en-US", which causes crPage.js to call Emulation.setUserAgentOverride during page init. Lightpanda does not implement that CDP command and returns UnknownMethod. An empty string is falsy, so the conditional (if options.locale) is skipped. Co-Authored-By: Claude --- apps/e2e-tests/playwright.lightpanda.config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/e2e-tests/playwright.lightpanda.config.ts b/apps/e2e-tests/playwright.lightpanda.config.ts index 5901144f6..cc1939313 100644 --- a/apps/e2e-tests/playwright.lightpanda.config.ts +++ b/apps/e2e-tests/playwright.lightpanda.config.ts @@ -13,6 +13,10 @@ export default defineConfig({ // video and screenshot disabled — Lightpanda has no rendering engine video: 'off', screenshot: 'off', + // Empty locale prevents Playwright from calling Emulation.setUserAgentOverride, + // which Lightpanda does not implement. Playwright's default is "en-US" which + // triggers that CDP command unconditionally (crPage.js: if options.locale → _updateUserAgent). + locale: '', }, projects: [ { From 4f5cb4ae753863eb5bf35a3e1226fa6a27e6a566 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Mon, 2 Mar 2026 10:29:16 +0100 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=90=9B=20fix(e2e):=20require=20{}=20d?= =?UTF-8?q?estructuring=20and=20remove=20browser.disconnect()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Playwright requires the first fixture argument to use object destructuring ({}) not a plain parameter; _fixtures caused a runtime error. Browser.disconnect() does not exist on CDP-connected browsers in playwright-core 1.56 — the connection closes naturally on worker exit. Co-Authored-By: Claude --- apps/e2e-tests/src/fixtures/packmindTest.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/e2e-tests/src/fixtures/packmindTest.ts b/apps/e2e-tests/src/fixtures/packmindTest.ts index 51da898dd..09c261a64 100644 --- a/apps/e2e-tests/src/fixtures/packmindTest.ts +++ b/apps/e2e-tests/src/fixtures/packmindTest.ts @@ -10,14 +10,16 @@ import { PageFactory } from '../infra/PageFactory'; // Override the built-in browser fixture to support Lightpanda via CDP const testBase = base.extend, { browser: Browser }>({ browser: [ - async (_fixtures, use) => { + // eslint-disable-next-line no-empty-pattern + async ({}, use) => { const wsEndpoint = process.env['LIGHTPANDA_WS_ENDPOINT']; if (wsEndpoint) { const browser = await chromium.connectOverCDP({ endpointURL: wsEndpoint, }); await use(browser as unknown as Browser); - await browser.disconnect(); + // Browser.disconnect() does not exist on CDP-connected browsers in playwright-core. + // The connection closes naturally when the worker process exits; Lightpanda keeps running. } else { const browser = await chromium.launch(); await use(browser);