@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 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`, sixty
75
- * seconds).
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 = 45_000;
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,
@@ -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
- | {| readonly status: "skipped", readonly reason: "explicit" | "not-only" | "filtered" |}
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" || test.body == null) {
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(test.body, timeoutMs);
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.31",
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.31"
29
+ "@uniflowed/host": "0.0.0-alpha.33"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "axe-core": ">=4"