@tekyzinc/gsd-t 4.4.11 → 4.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,81 +0,0 @@
1
- /**
2
- * launch-extension.ts — GSD-T template: launch Chromium with an unpacked MV3
3
- * extension WITHOUT stealing focus or taking over the developer's screen.
4
- *
5
- * Copy into e2e/helpers/ and set EXTENSION_PATH for your project.
6
- * Origin: binvoice 2026-06-10 (see GSD-T CHANGELOG 4.4.11).
7
- *
8
- * THE INVARIANT: E2E tests must NEVER steal keyboard focus. On macOS a headed
9
- * Chromium launch ACTIVATES the app — yanking the cursor out of the terminal —
10
- * regardless of window position. Off-screen windows do NOT fix this; only a
11
- * truly headless launch does.
12
- *
13
- * Modes:
14
- * 1. NEW HEADLESS (DEFAULT) — full-Chromium new headless via
15
- * `channel: 'chromium'` + `headless: true`. Loads MV3 extensions and
16
- * registers service workers. No window, no activation, no focus theft.
17
- * PITFALL this template exists to encode: `headless: true` ALONE launches
18
- * Playwright's chromium_headless_shell (OLD headless — silently cannot
19
- * load extensions), and passing `--headless=new` as a raw arg fights that
20
- * binary instead of selecting the right one. `channel: 'chromium'` is the
21
- * load-bearing line.
22
- * 2. OFF-SCREEN HEADED — fallback if a future Chrome regresses new-headless
23
- * extension support. Prevents screen takeover but NOT macOS focus theft.
24
- * 3. HEADED — visible window for watching a run. Opt-in only, never default.
25
- *
26
- * Env:
27
- * HEADED=1 → mode 3 (visible window).
28
- * E2E_MODE=offscreen → mode 2 (fallback).
29
- * (unset) → mode 1 (new headless — the default).
30
- */
31
-
32
- import { chromium, type BrowserContext } from '@playwright/test';
33
- import { resolve } from 'path';
34
-
35
- // Adjust for your project: path to the built unpacked extension.
36
- export const EXTENSION_PATH = resolve(__dirname, '../../dist');
37
-
38
- type Mode = 'newheadless' | 'offscreen' | 'headed';
39
-
40
- function resolveMode(): Mode {
41
- if (process.env['HEADED'] === '1') return 'headed';
42
- if (process.env['E2E_MODE'] === 'offscreen') return 'offscreen';
43
- if (process.env['E2E_MODE'] === 'headed') return 'headed';
44
- return 'newheadless';
45
- }
46
-
47
- function baseArgs(): string[] {
48
- return [
49
- `--disable-extensions-except=${EXTENSION_PATH}`,
50
- `--load-extension=${EXTENSION_PATH}`,
51
- '--no-sandbox',
52
- ];
53
- }
54
-
55
- export async function launchExtensionContext(): Promise<BrowserContext> {
56
- const mode = resolveMode();
57
- const args = baseArgs();
58
-
59
- if (mode === 'newheadless') {
60
- return chromium.launchPersistentContext('', {
61
- channel: 'chromium', // load-bearing: full build → new headless → extensions work
62
- headless: true,
63
- args,
64
- });
65
- }
66
-
67
- if (mode === 'offscreen') {
68
- return chromium.launchPersistentContext('', {
69
- headless: false,
70
- args: [
71
- ...args,
72
- '--window-position=-2400,-2400',
73
- '--window-size=400,300',
74
- '--no-first-run',
75
- '--no-default-browser-check',
76
- ],
77
- });
78
- }
79
-
80
- return chromium.launchPersistentContext('', { headless: false, args });
81
- }