@uniflowed/test 0.5.0 → 0.6.0

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,5 +1,6 @@
1
1
  // @flow
2
2
  import type { BrowserTransport, ControlOptions } from "./cdp.js";
3
+ import { runnerFetch } from "./runner-fetch.js";
3
4
 
4
5
  export async function createTransport(options: ControlOptions): Promise<BrowserTransport> {
5
6
  if (options.executable != null)
@@ -12,7 +13,8 @@ export async function createTransport(options: ControlOptions): Promise<BrowserT
12
13
  method: string,
13
14
  args: $ReadOnlyArray<mixed> = [],
14
15
  ): Promise<$FlowFixMe> {
15
- const response = await fetch("/uf-test/browser", {
16
+ // The platform's `fetch`, not the global a test's request mock replaced.
17
+ const response = await runnerFetch("/uf-test/browser", {
16
18
  method: "POST",
17
19
  headers: { "content-type": "application/json", "uf-test-browser": token },
18
20
  body: JSON.stringify({ id, method, args }),
@@ -37,6 +37,7 @@
37
37
  import * as output from "../output.js";
38
38
  import { run } from "../run.js";
39
39
  import { installInSourceTests } from "../../in-source.js";
40
+ import { runnerFetch } from "./runner-fetch.js";
40
41
 
41
42
  /** One file, as the server hands it over. */
42
43
  type PageRequest = {
@@ -74,7 +75,9 @@ function flush(): Promise<void> {
74
75
  if (already != null) return already;
75
76
  if (queue.length === 0) return Promise.resolve();
76
77
  const batch = queue.splice(0, queue.length);
77
- const sent = fetch("/uf-test/events", {
78
+ // Not the global: a file that installed a request mock owns that one, and
79
+ // would answer the runner's report as an unhandled request.
80
+ const sent = runnerFetch("/uf-test/events", {
78
81
  method: "POST",
79
82
  headers: { "content-type": "application/json" },
80
83
  body: JSON.stringify(batch),
@@ -195,7 +198,7 @@ function page(): $FlowFixMe {
195
198
  async function serve(): Promise<void> {
196
199
  let request: PageRequest;
197
200
  try {
198
- request = await (await fetch("/uf-test/next")).json();
201
+ request = await (await runnerFetch("/uf-test/next")).json();
199
202
  } catch {
200
203
  // The driver has gone. Nothing to report it to.
201
204
  return;
@@ -0,0 +1,38 @@
1
+ // @flow
2
+ //
3
+ // Internal to `@uniflowed/test`: the `fetch` the browser runner talks to `uf`
4
+ // with.
5
+ //
6
+ // A page reports its results over HTTP — `POST /uf-test/events`, and
7
+ // `POST /uf-test/browser` for `createBrowser` — and the file under test runs
8
+ // in that same page. A file that installs a request mock replaces
9
+ // `globalThis.fetch`, and `@uniflowed/mock`'s default policy rejects every
10
+ // request no handler claimed. Reached through the global, the runner's own
11
+ // requests would be answered by the test's mock: rejected, and the rejection
12
+ // swallowed by the reporter, so the results would never reach `uf test`
13
+ // (ubugeeei-prod/uf#1394).
14
+ //
15
+ // So the harness captures the platform's `fetch` in a classic script that runs
16
+ // before any module — before the runner, and so before any test file could
17
+ // replace it — and the runner's requests go through that capture. A constant
18
+ // captured in this module would depend on when it was first evaluated and on
19
+ // `page.js` and the import map reaching it by the same URL; the harness
20
+ // script depends on neither.
21
+
22
+ /** Where `server.js`'s harness leaves the platform's `fetch`. */
23
+ export const RUNNER_FETCH: symbol = Symbol.for("uf.test.browser.fetch");
24
+
25
+ /**
26
+ * `fetch`, as it was before any test file ran.
27
+ *
28
+ * Falls back to the global when nothing was captured, which is a page not
29
+ * served by `uf test --browser` — there is no test file ahead of it to have
30
+ * replaced anything.
31
+ */
32
+ export function runnerFetch(input: RequestInfo, init?: RequestOptions): Promise<Response> {
33
+ const captured = Reflect.get(globalThis, RUNNER_FETCH);
34
+ if (typeof captured === "function") {
35
+ return captured(input, init);
36
+ }
37
+ return fetch(input, init);
38
+ }
@@ -639,6 +639,10 @@ function harnessHtml(map: string, browserToken: string): string {
639
639
  '<meta charset="utf-8">',
640
640
  "<title>uf test</title>",
641
641
  `<script>globalThis[Symbol.for("uf.test.browser.token")]=${JSON.stringify(browserToken)}</script>`,
642
+ // Before any module, so before any test file can replace it: the runner
643
+ // reports through this `fetch`, never through a mocked global. See
644
+ // `./runner-fetch.js`.
645
+ '<script>globalThis[Symbol.for("uf.test.browser.fetch")]=globalThis.fetch.bind(globalThis)</script>',
642
646
  `<script type="importmap">${map}</script>`,
643
647
  `<script type="module" src="${page}"></script>`,
644
648
  "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniflowed/test",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
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",
@@ -38,7 +38,7 @@
38
38
  "!*.test.js"
39
39
  ],
40
40
  "dependencies": {
41
- "@uniflowed/host": "0.5.0",
41
+ "@uniflowed/host": "0.6.0",
42
42
  "pixelmatch": "^7.1.0",
43
43
  "pngjs": "^7.0.0"
44
44
  },