From 1fef27a9d369ffb6e8a7b25e300c6fe3e00b756d Mon Sep 17 00:00:00 2001 From: Isolator acm Date: Mon, 22 Jun 2026 09:35:32 +0200 Subject: [PATCH] test(e2e): add a Playwright harness + regression test for editor scroll alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit happy-dom has no real layout or scrollbars, so the editor highlight/selection alignment bug (a textarea scrollbar shrinking its client box, clamping the highlight
 behind the selection on scroll) couldn't be caught at the unit
layer — it regressed twice. This adds a minimal real-browser layer for exactly
that class of bug.

- playwright.config.js: serves the repo over python http.server so the harness
  imports the *actual* src/ modules as native ESM (no bundling); chromium.
- tests/e2e/editor.html: mounts the real editor with a stub controller.
- tests/e2e/editor-alignment.spec.js: loads a tall query whose last line forces
  a horizontal scrollbar, scrolls to the bottom, and asserts the textarea and
  highlight keep equal client boxes and the same scroll offset. Verified the
  assertions fail on the pre-fix state and pass on the fix (negative-checked in
  a real engine).
- package.json: @playwright/test devDep + `npm run test:e2e`. Separate from
  `npm test` and the coverage gate.
- README + .gitignore updated.

Co-Authored-By: Claude Opus 4.8 
Claude-Session: https://claude.ai/code/session_01QennTvGKAtJZrv9EpQagef
---
 .gitignore                         |  2 ++
 README.md                          | 16 +++++++++++
 package.json                       |  2 ++
 playwright.config.js               | 25 +++++++++++++++++
 tests/e2e/editor-alignment.spec.js | 44 ++++++++++++++++++++++++++++++
 tests/e2e/editor.html              | 36 ++++++++++++++++++++++++
 6 files changed, 125 insertions(+)
 create mode 100644 playwright.config.js
 create mode 100644 tests/e2e/editor-alignment.spec.js
 create mode 100644 tests/e2e/editor.html

diff --git a/.gitignore b/.gitignore
index 47e94a8..402d0ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,8 @@
 
 # Test / coverage
 /coverage/
+/test-results/
+/playwright-report/
 
 # Dependencies (reuse a sibling install or `npm ci`)
 # No trailing slash so a `node_modules` symlink is ignored too.
diff --git a/README.md b/README.md
index 8201762..b25d937 100644
--- a/README.md
+++ b/README.md
@@ -169,6 +169,22 @@ and the bootstrap — is held at **100/100/100/100** (statements / branches /
 functions / lines). The fetch, crypto, and storage seams are injected, so the
 suite needs no mocking libraries.
 
+### End-to-end (real browser)
+
+happy-dom has no real layout or scrollbars, so render-layer bugs (e.g. the
+editor highlight drifting behind the selection when a scrollbar shrinks the
+textarea's client box) can't be caught by the unit suite. A small Playwright
+harness mounts the real `src/` modules in Chromium for those cases.
+
+```bash
+npx playwright install chromium   # once per machine
+npm run test:e2e
+```
+
+The harness (`tests/e2e/`) serves the repo over HTTP and imports the actual
+source as native ESM — no bundling, always current. It is **not** part of
+`npm test` or the coverage gate.
+
 ## License
 
 Apache-2.0.
diff --git a/package.json b/package.json
index 9e8a25b..bed332f 100644
--- a/package.json
+++ b/package.json
@@ -9,9 +9,11 @@
     "build": "node build/build.mjs",
     "test": "vitest run --coverage --config tests/vitest.config.ts",
     "test:watch": "vitest --config tests/vitest.config.ts",
+    "test:e2e": "playwright test",
     "dev": "node build/build.mjs && python3 -m http.server -d dist 8900"
   },
   "devDependencies": {
+    "@playwright/test": "^1.48.0",
     "@vitest/coverage-v8": "^2.1.8",
     "esbuild": "^0.21.5",
     "happy-dom": "^15.11.0",
diff --git a/playwright.config.js b/playwright.config.js
new file mode 100644
index 0000000..1475f66
--- /dev/null
+++ b/playwright.config.js
@@ -0,0 +1,25 @@
+import { defineConfig } from '@playwright/test';
+
+// Real-browser regression tests. happy-dom (the unit layer) has no scrollbar or
+// real box layout, so render-layer bugs — e.g. the editor's highlight drifting
+// behind the selection when a scrollbar shrinks the textarea's client box —
+// can only be caught in a real engine. These run separately from `npm test`.
+//
+// Setup once per machine: `npx playwright install chromium`.
+// Run: `npm run test:e2e`.
+export default defineConfig({
+  testDir: './tests/e2e',
+  testMatch: '**/*.spec.js',
+  // Serve the repo root over HTTP so the harness can import the *actual* source
+  // modules (/src/**) as native ESM — no bundling, always current.
+  webServer: {
+    command: 'python3 -m http.server -d . 5599',
+    url: 'http://127.0.0.1:5599/tests/e2e/editor.html',
+    reuseExistingServer: !process.env.CI,
+    timeout: 30_000,
+  },
+  use: {
+    baseURL: 'http://127.0.0.1:5599',
+    browserName: 'chromium',
+  },
+});
diff --git a/tests/e2e/editor-alignment.spec.js b/tests/e2e/editor-alignment.spec.js
new file mode 100644
index 0000000..cdcd4c3
--- /dev/null
+++ b/tests/e2e/editor-alignment.spec.js
@@ -0,0 +1,44 @@
+import { test, expect } from '@playwright/test';
+
+// Regression guard for the editor's highlight/selection alignment.
+//
+// The bug: a long line gives the