@uniflowed/test 0.0.0-alpha.31 → 0.0.0-alpha.33
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.
- package/browser-worker.js +25 -3
- package/internal/registry.js +6 -0
- package/internal/run.js +14 -5
- package/package.json +2 -2
package/browser-worker.js
CHANGED
|
@@ -71,15 +71,15 @@ type Request = {|
|
|
|
71
71
|
*
|
|
72
72
|
* Generous against a cold Chromium with a cold profile, which is about seven
|
|
73
73
|
* seconds on a laptop and much worse in a busy container, and deliberately
|
|
74
|
-
* *shorter than `uf_test`'s browser file budget* (`BROWSER_FILE_TIMEOUT`,
|
|
75
|
-
*
|
|
74
|
+
* *shorter than `uf_test`'s browser file budget* (`BROWSER_FILE_TIMEOUT`, two
|
|
75
|
+
* minutes).
|
|
76
76
|
* That order is the whole point: `uf` is already holding a stopwatch on the
|
|
77
77
|
* first file while this is happening, and whichever of the two fires first is
|
|
78
78
|
* what the report says. A browser that will not start should be reported as a
|
|
79
79
|
* browser that will not start, with its own output attached — not as a file
|
|
80
80
|
* that timed out, which is a sentence about tests that were never reached.
|
|
81
81
|
*/
|
|
82
|
-
const START_TIMEOUT_MS =
|
|
82
|
+
const START_TIMEOUT_MS = 110_000;
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* The switches a headless run needs, and what each is for.
|
|
@@ -117,8 +117,25 @@ function browserArguments(profile: string, url: string): Array<string> {
|
|
|
117
117
|
// A scratch profile per run: no extensions, no saved state, no policy from
|
|
118
118
|
// the developer's own browser leaking into what the suite measures.
|
|
119
119
|
`--user-data-dir=${profile}`,
|
|
120
|
+
// The scratch profile stores no credentials, so keep Chrome off desktop
|
|
121
|
+
// keyring backends that can hang behind a broken CI DBus session before
|
|
122
|
+
// the first page request.
|
|
123
|
+
"--password-store=basic",
|
|
120
124
|
"--no-first-run",
|
|
121
125
|
"--no-default-browser-check",
|
|
126
|
+
// Keep startup deterministic in CI. These cut services Chrome may start
|
|
127
|
+
// before the first page request: extensions, sync, updater probes, and
|
|
128
|
+
// background network clients such as GCM. None of them changes layout or
|
|
129
|
+
// module execution, which is what browser mode measures.
|
|
130
|
+
"--disable-background-networking",
|
|
131
|
+
"--disable-client-side-phishing-detection",
|
|
132
|
+
"--disable-component-update",
|
|
133
|
+
"--disable-default-apps",
|
|
134
|
+
"--disable-domain-reliability",
|
|
135
|
+
"--disable-extensions",
|
|
136
|
+
"--disable-sync",
|
|
137
|
+
"--disable-features=AutofillServerCommunication,BackgroundFetch,BackgroundSync,CertificateTransparencyComponentUpdater,DialMediaRouteProvider,MediaRouter,NotificationTriggers,OptimizationHints,PushMessaging,Translate",
|
|
138
|
+
"--metrics-recording-only",
|
|
122
139
|
// Nothing here paints, and a GPU process is one more thing to fail in a
|
|
123
140
|
// container.
|
|
124
141
|
"--disable-gpu",
|
|
@@ -210,6 +227,11 @@ async function main(): Promise<void> {
|
|
|
210
227
|
const child = spawn(browser, browserArguments(profile, server.url), {
|
|
211
228
|
stdio: ["ignore", "pipe", "pipe", "pipe", "pipe"],
|
|
212
229
|
});
|
|
230
|
+
// The DevTools pipe is a lifeline, not a protocol this driver speaks. Chrome
|
|
231
|
+
// can still write target bookkeeping to fd 4 before the page asks for work;
|
|
232
|
+
// drain it so a full pipe cannot block startup before the first HTTP request.
|
|
233
|
+
const devtoolsOutput = child.stdio[4];
|
|
234
|
+
devtoolsOutput?.on("data", () => {});
|
|
213
235
|
// Kept, not printed. A Chromium writes a dozen lines about GPU probing and
|
|
214
236
|
// Vulkan on a healthy start, and forwarding those to a passing run's report
|
|
215
237
|
// would be noise; they are the whole of the evidence when it does not start,
|
package/internal/registry.js
CHANGED
|
@@ -36,6 +36,7 @@ export type Case = {|
|
|
|
36
36
|
readonly name: string,
|
|
37
37
|
readonly body: Body | null,
|
|
38
38
|
readonly modifier: Modifier,
|
|
39
|
+
readonly skipReason: string | null,
|
|
39
40
|
readonly timeoutMs: number | null,
|
|
40
41
|
readonly line: number,
|
|
41
42
|
readonly column: number,
|
|
@@ -123,6 +124,7 @@ function addCase(
|
|
|
123
124
|
body: Body | null,
|
|
124
125
|
modifier: Modifier,
|
|
125
126
|
timeoutMs: number | null,
|
|
127
|
+
skipReason: string | null = null,
|
|
126
128
|
): void {
|
|
127
129
|
const position = callSite();
|
|
128
130
|
current.children.push({
|
|
@@ -130,6 +132,7 @@ function addCase(
|
|
|
130
132
|
name,
|
|
131
133
|
body,
|
|
132
134
|
modifier,
|
|
135
|
+
skipReason,
|
|
133
136
|
timeoutMs,
|
|
134
137
|
line: position.line,
|
|
135
138
|
column: position.column,
|
|
@@ -179,6 +182,9 @@ function caseApi(): $FlowFixMe {
|
|
|
179
182
|
api.skip = (name: string, body?: Body) => {
|
|
180
183
|
addCase(name, body ?? null, "skip", null);
|
|
181
184
|
};
|
|
185
|
+
api.skipBecause = (name: string, reason: string, body?: Body) => {
|
|
186
|
+
addCase(name, body ?? null, "skip", null, reason);
|
|
187
|
+
};
|
|
182
188
|
api.todo = (name: string, body?: Body) => {
|
|
183
189
|
addCase(name, body ?? null, "todo", null);
|
|
184
190
|
};
|
package/internal/run.js
CHANGED
|
@@ -27,7 +27,11 @@ export type Outcome =
|
|
|
27
27
|
/** Where the failing assertion was written, when the stack says. */
|
|
28
28
|
readonly site: {| readonly line: number, readonly column: number |} | null,
|
|
29
29
|
|}
|
|
30
|
-
| {|
|
|
30
|
+
| {|
|
|
31
|
+
readonly status: "skipped",
|
|
32
|
+
readonly reason: "explicit" | "not-only" | "filtered",
|
|
33
|
+
readonly message?: string | null,
|
|
34
|
+
|}
|
|
31
35
|
| {| readonly status: "todo" |};
|
|
32
36
|
|
|
33
37
|
/** One finished case, as the runner reports it. */
|
|
@@ -188,12 +192,17 @@ async function runCase(
|
|
|
188
192
|
});
|
|
189
193
|
};
|
|
190
194
|
|
|
191
|
-
if (test.modifier === "todo"
|
|
195
|
+
if (test.modifier === "todo") {
|
|
192
196
|
report({ status: "todo" });
|
|
193
197
|
return true;
|
|
194
198
|
}
|
|
195
199
|
if (context.skipped || test.modifier === "skip") {
|
|
196
|
-
report({ status: "skipped", reason: "explicit" });
|
|
200
|
+
report({ status: "skipped", reason: "explicit", message: test.skipReason });
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
const body = test.body;
|
|
204
|
+
if (body == null) {
|
|
205
|
+
report({ status: "todo" });
|
|
197
206
|
return true;
|
|
198
207
|
}
|
|
199
208
|
if (!context.onlyPath) {
|
|
@@ -222,7 +231,7 @@ async function runCase(
|
|
|
222
231
|
for (const hook of context.beforeEach) {
|
|
223
232
|
await withTimeout(hook, timeoutMs);
|
|
224
233
|
}
|
|
225
|
-
await withTimeout(
|
|
234
|
+
await withTimeout(body, timeoutMs);
|
|
226
235
|
} catch (thrown) {
|
|
227
236
|
outcome = failure(thrown, options.file ?? null);
|
|
228
237
|
}
|
|
@@ -315,7 +324,7 @@ async function runSuite(
|
|
|
315
324
|
line: child.line,
|
|
316
325
|
column: child.column,
|
|
317
326
|
durationMicros: 0,
|
|
318
|
-
outcome: failure(thrown),
|
|
327
|
+
outcome: failure(thrown, options.file ?? null),
|
|
319
328
|
});
|
|
320
329
|
passed = false;
|
|
321
330
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniflowed/test",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.33",
|
|
4
4
|
"description": "The test API and worker for `uf test`: describe/it, a full matcher set, and the process uf fans test files out to.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"!*.test.js"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@uniflowed/host": "0.0.0-alpha.
|
|
29
|
+
"@uniflowed/host": "0.0.0-alpha.33"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"axe-core": ">=4"
|