-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathplaywright.config.ts
More file actions
140 lines (131 loc) · 4.7 KB
/
Copy pathplaywright.config.ts
File metadata and controls
140 lines (131 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
* Hermetic e2e stack — no API keys, no external services, no network.
*
* The `webServer` array below is the startup order, and it is load-bearing: the app throws at
* boot without `${OPENAI_BASE_URL}/models` and `process.exit(1)`s without Mongo, so both must be
* listening first. `globalSetup` cannot do this — the runner builds `webServer` tasks before
* global-setup tasks.
*
* Addresses are always IP literals, never `localhost`: `ssrfSafeFetch` blocks `localhost` (it
* resolves to `::1`) but allows literals, since undici only runs its SSRF `lookup` hook for
* hostnames needing DNS.
*
* Serial because one app and one database are shared and the `db` fixture wipes between tests.
* Raising `PLAYWRIGHT_WORKERS` also means scoping scenarios per conversation and rethinking the
* wipe.
*/
import { defineConfig, devices } from "playwright/test";
import {
E2E_APP_PORT,
E2E_APP_URL,
E2E_DB_NAME,
E2E_MONGO_PORT,
E2E_MONGO_URL,
MOCK_MCP_ORIGIN,
MOCK_OPENAI_BASE_URL,
MOCK_OPENAI_ORIGIN,
} from "./tests/fixtures.ts";
/** Node < 22.18 needs the flag; on newer versions it is accepted and inert. */
const NODE_TS = "node --experimental-strip-types --no-warnings";
const isCI = Boolean(process.env.CI);
export default defineConfig({
testDir: "./tests",
testMatch: /.*\.spec\.ts/,
outputDir: "./test-results",
fullyParallel: false,
workers: Number(process.env.PLAYWRIGHT_WORKERS ?? 1),
forbidOnly: isCI,
retries: isCI ? 2 : 0,
timeout: 60_000,
expect: { timeout: 15_000 },
reporter: isCI
? [["list"], ["html", { outputFolder: "playwright-report", open: "never" }]]
: [["list"]],
use: {
baseURL: E2E_APP_URL,
trace: "on-first-retry",
screenshot: "only-on-failure",
video: "retain-on-failure",
},
projects: [
{ name: "chromium", use: { ...devices["Desktop Chrome"] } },
// Not optional — the worst regression cluster in this repo is Safari-specific scroll and
// layout behaviour.
{ name: "webkit", use: { ...devices["Desktop Safari"] } },
],
webServer: [
{
// Database first — the app exits if it cannot connect.
command: `${NODE_TS} tests/fixtures.ts`,
port: E2E_MONGO_PORT,
reuseExistingServer: !isCI,
timeout: 120_000,
stdout: "pipe",
stderr: "pipe",
},
{
// Then the LLM upstream — the app throws at boot without /v1/models.
command: `${NODE_TS} tests/mock-openai.ts`,
url: `${MOCK_OPENAI_ORIGIN}/__control/health`,
reuseExistingServer: !isCI,
timeout: 30_000,
stdout: "pipe",
stderr: "pipe",
},
{
command: `${NODE_TS} tests/mock-mcp.ts`,
url: `${MOCK_MCP_ORIGIN}/health`,
reuseExistingServer: !isCI,
timeout: 30_000,
stdout: "pipe",
stderr: "pipe",
},
{
// The app last, through `server.js` — the same entry point production uses, rather than
// `vite preview`. Two reasons: it exercises the polka compression config that keeps
// `application/jsonl` unbuffered, and it loads no vite/svelte config, so the
// `dotenv.config({ override: true })` in svelte.config.js cannot replace the hermetic
// values below with whatever a developer has in `.env.local`.
command: `npm run build && node server.js`,
url: E2E_APP_URL,
reuseExistingServer: !isCI,
timeout: 300_000,
// Request logging at info level buries the test results; errors still reach stderr.
stdout: "ignore",
stderr: "pipe",
env: {
HOST: "127.0.0.1",
PORT: String(E2E_APP_PORT),
LOG_LEVEL: "warn",
OPENAI_BASE_URL: MOCK_OPENAI_BASE_URL,
OPENAI_API_KEY: "e2e-test-key",
MONGODB_URL: E2E_MONGO_URL,
MONGODB_DB_NAME: E2E_DB_NAME,
MONGODB_DIRECT_CONNECTION: "true",
PUBLIC_ORIGIN: E2E_APP_URL,
PUBLIC_APP_ASSETS: "chatui",
COOKIE_NAME: "hf-chat",
// A production build defaults `secure` to true and the app re-sets the session
// cookie on every POST. Playwright's APIRequestContext enforces `Secure` strictly
// over plain HTTP, so without this every `request.post` lands on a new session.
COOKIE_SECURE: "false",
COOKIE_SAMESITE: "lax",
// Deterministic surface: no DB-driven config, no router, no ambient MCP servers.
ENABLE_CONFIG_MANAGER: "false",
MCP_SERVERS: "[]",
// Without this the SSRF guard drops every loopback MCP URL a spec passes.
MCP_ALLOW_INSECURE_URLS: "true",
// Scaled down together (production is 60000 / 90000 / 10000) so a reaper
// test sees a dead run finalized within its lifetime, while a live run
// heartbeating every second stays comfortably under the 5s stale threshold.
GENERATION_REAP_INTERVAL_MS: "1000",
GENERATION_REAP_AFTER_MS: "5000",
GENERATION_HEARTBEAT_MS: "1000",
LLM_ROUTER_ROUTES_PATH: "",
LLM_ROUTER_ARCH_BASE_URL: "",
ALLOW_IFRAME: "true",
NODE_ENV: "production",
},
},
],
});