@uniflowed/test 0.0.0-alpha.18 → 0.0.0-alpha.20

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.
@@ -50,8 +50,11 @@ const stubbedGlobals: Map<string, { readonly owned: boolean, readonly value: mix
50
50
  /**
51
51
  * Read the process environment, whichever host this is.
52
52
  *
53
- * Node, Deno and Bun all expose `process.env`; Deno also has `Deno.env`, and
54
- * reaching for `process` first keeps one code path across the three.
53
+ * Node and Bun expose `process` as a global; **Deno does not**, and has the
54
+ * same object under `node:process`. `../worker.js` installs it on the global
55
+ * before anything here runs, which is what keeps this one code path across the
56
+ * three — and is why the `null` branch below is still reachable, for a host
57
+ * that is neither.
55
58
  */
56
59
  function environment(): { [string]: string } | null {
57
60
  const host = globalThis as $FlowFixMe;
@@ -241,6 +241,19 @@ function writer(
241
241
  * Installed once, for the life of the worker: a worker runs many files, and
242
242
  * restoring the real methods between them would leave a window in which a
243
243
  * straggling `setTimeout` from the previous file writes into the protocol.
244
+ *
245
+ * # A page has no stream to take
246
+ *
247
+ * `uf test --browser` runs this same capture inside a page
248
+ * (`./browser/page.js`), and there the whole premise of the returned value is
249
+ * absent: there is no `process.stdout`, so there is nothing for a test to
250
+ * write into by accident, and the protocol's channel is a separate HTTP
251
+ * request rather than a stream anything else can reach. So the two `write`
252
+ * methods are only replaced when there are two `write` methods, and the
253
+ * "raw stream" handed back is a no-op nobody has a use for.
254
+ *
255
+ * Deliberately not a `typeof process` check at each use: the question is asked
256
+ * once, here, because the answer cannot change under a running host.
244
257
  */
245
258
  export function install(to: OutputSink): (chunk: string) => void {
246
259
  const global = host();
@@ -248,11 +261,14 @@ export function install(to: OutputSink): (chunk: string) => void {
248
261
  if (already != null) {
249
262
  return already;
250
263
  }
251
- const stdout = global.process.stdout;
252
- const real = stdout.write;
253
- const protocol = (chunk: string) => {
254
- real.call(stdout, chunk);
255
- };
264
+ const stdout = global.process?.stdout;
265
+ const real = stdout?.write;
266
+ const protocol =
267
+ real == null
268
+ ? (_chunk: string) => {}
269
+ : (chunk: string) => {
270
+ real.call(stdout, chunk);
271
+ };
256
272
  raw = protocol;
257
273
  sink = to;
258
274
  for (const method of Object.keys(CONSOLE_STREAMS)) {
@@ -271,8 +287,10 @@ export function install(to: OutputSink): (chunk: string) => void {
271
287
  capture("stderr", `${userFrames(error.stack) ?? `Trace: ${error.message}`}\n`);
272
288
  };
273
289
 
274
- global.process.stdout.write = writer("stdout");
275
- global.process.stderr.write = writer("stderr");
290
+ if (global.process?.stdout != null) {
291
+ global.process.stdout.write = writer("stdout");
292
+ global.process.stderr.write = writer("stderr");
293
+ }
276
294
  return protocol;
277
295
  }
278
296
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniflowed/test",
3
- "version": "0.0.0-alpha.18",
3
+ "version": "0.0.0-alpha.20",
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",
@@ -14,16 +14,19 @@
14
14
  ".": "./index.js",
15
15
  "./in-source": "./in-source.js",
16
16
  "./worker": "./worker.js",
17
+ "./browser-worker": "./browser-worker.js",
17
18
  "./package.json": "./package.json"
18
19
  },
19
20
  "files": [
21
+ "browser-worker.js",
20
22
  "in-source.js",
21
23
  "index.js",
22
24
  "internal",
23
- "worker.js"
25
+ "worker.js",
26
+ "!*.test.js"
24
27
  ],
25
28
  "dependencies": {
26
- "@uniflowed/host": "0.0.0-alpha.18"
29
+ "@uniflowed/host": "0.0.0-alpha.20"
27
30
  },
28
31
  "peerDependencies": {
29
32
  "axe-core": ">=4"
package/worker.js CHANGED
@@ -49,6 +49,7 @@
49
49
 
50
50
  import * as output from "./internal/output.js";
51
51
  import { AsyncLocalStorage } from "node:async_hooks";
52
+ import process from "node:process";
52
53
  import { writeChangedSnapshots } from "./internal/snapshot.js";
53
54
  import { createInterface } from "node:readline";
54
55
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -57,6 +58,27 @@ import { installInSourceTests } from "./in-source.js";
57
58
  import { restoreSharedState } from "./internal/isolation.js";
58
59
  import { run } from "./internal/run.js";
59
60
 
61
+ // `process` is imported rather than read off the global, and then put *on*
62
+ // the global, because one host in three does not have it there.
63
+ //
64
+ // Deno exposes the whole object as `node:process` and nothing as
65
+ // `globalThis.process` — `crates/uf_cli/tests/deno_host.rs` starts a real one
66
+ // and asserts both halves. Every module this worker reaches that wants the
67
+ // process reaches for the global: `internal/output.js` replaces
68
+ // `process.stdout.write` so a test's printing cannot land in the middle of the
69
+ // protocol, `internal/namespace.js` reads `process.env` for `stubEnv`, and
70
+ // `internal/axe.js` reads `UF_AXE` from it. Threading an import through all
71
+ // three would put a `node:` specifier into modules a browser build resolves,
72
+ // for a difference no other host has.
73
+ //
74
+ // So the entry point installs it, once, before anything below runs. `??=`
75
+ // rather than `=`: on Node and Bun the global is already the real object and
76
+ // this must not replace it with a second view of the same thing.
77
+ //
78
+ // It is a shim of the host, in the one file that is a process entry point, and
79
+ // it stops here — nothing else in `@uniflowed/test` may do this.
80
+ globalThis.process ??= process;
81
+
60
82
  /** What `uf` sends for one file. */
61
83
  type Request = {|
62
84
  readonly file: string,