@uniflowed/test 0.0.0-alpha.6 → 0.0.0-alpha.7

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.
@@ -16,11 +16,24 @@
16
16
  /** A position in a source file, one-based line and column. */
17
17
  export type Site = {| readonly line: number, readonly column: number |};
18
18
 
19
- /** Frames belonging to the runner itself, which no test author wrote. */
19
+ /**
20
+ * Frames belonging to the testing libraries, which no test author wrote.
21
+ *
22
+ * `@uniflowed/react-testing` is here for exactly the reason `@uniflowed/test`
23
+ * is, and was missing because it is a different package. Every `getBy…`
24
+ * failure is *constructed* inside it, so the first surviving frame of the
25
+ * commonest failure a component test can produce was `internal/queries.js` —
26
+ * and since a site is reported as a line of the file being run, the reader was
27
+ * sent to a line their own file does not have. That is ubugeeei-prod/uf#319.
28
+ * A library that raises on the caller's behalf is the runner as far as the
29
+ * report is concerned.
30
+ */
20
31
  const INTERNAL_MARKERS = [
21
32
  "/packages/test/internal/",
22
33
  "/packages/test/worker.js",
34
+ "/packages/react-testing/",
23
35
  "/@uniflowed/test/",
36
+ "/@uniflowed/react-testing/",
24
37
  "node:internal/",
25
38
  ];
26
39
 
@@ -93,6 +106,36 @@ export function firstUserSite(
93
106
  return null;
94
107
  }
95
108
 
109
+ /**
110
+ * The first position in `stack` that is in `file`, or `null`.
111
+ *
112
+ * The reporter draws a failure's position as `path:line:column`, and it takes
113
+ * the path from the file it asked the worker to run rather than from the
114
+ * frame. So a number lifted from any other file is not a vaguer answer than
115
+ * none — it is a wrong one, naming a line the reader can open and that has
116
+ * nothing to do with what failed. Restricting the search to the file that will
117
+ * be named makes the two halves of that position come from the same place.
118
+ *
119
+ * `null` when the file is on no frame, which is a failure raised from work the
120
+ * case left behind: no line of it is the one that failed, and printing none is
121
+ * the honest answer.
122
+ */
123
+ export function siteInFile(stack: string | null | void, file: string): Site | null {
124
+ if (stack == null) {
125
+ return null;
126
+ }
127
+ for (const frame of stack.split("\n").slice(1)) {
128
+ if (!frame.includes(file)) {
129
+ continue;
130
+ }
131
+ const site = frameSite(frame);
132
+ if (site != null) {
133
+ return site;
134
+ }
135
+ }
136
+ return null;
137
+ }
138
+
96
139
  /**
97
140
  * `stack` with the runner's own frames removed.
98
141
  *
package/internal/run.js CHANGED
@@ -12,7 +12,7 @@
12
12
  import * as output from "./output.js";
13
13
  import * as snapshot from "./snapshot.js";
14
14
  import { AssertionError } from "./expect.js";
15
- import { firstUserSite, userFrames } from "./frames.js";
15
+ import { type Site, firstUserSite, siteInFile, userFrames } from "./frames.js";
16
16
  import { type Body, type Case, type Suite, collected } from "./registry.js";
17
17
 
18
18
  /** How one case ended. */
@@ -102,7 +102,22 @@ async function withTimeout(body: Body, timeoutMs: number): Promise<void> {
102
102
  }
103
103
  }
104
104
 
105
- function failure(thrown: mixed): Outcome {
105
+ /**
106
+ * Where to say a failure happened.
107
+ *
108
+ * The reported position is printed under the path of the file being run, so
109
+ * when that file is known the line has to come from it: `firstUserSite` will
110
+ * hand back the first frame of whatever library raised, and a library's line
111
+ * number wearing the test file's path sends the reader to the wrong place
112
+ * (ubugeeei-prod/uf#319). The fallback is for a caller that did not say which
113
+ * file it is running — `run` is driven directly by this repository's own
114
+ * tests as well as by the worker — and is what every failure used before.
115
+ */
116
+ function siteOf(stack: string | null, file: string | null): Site | null {
117
+ return file == null || file === "" ? firstUserSite(stack, false) : siteInFile(stack, file);
118
+ }
119
+
120
+ function failure(thrown: mixed, file: string | null): Outcome {
106
121
  if (thrown instanceof AssertionError) {
107
122
  const stack = userFrames(thrown.stack);
108
123
  return {
@@ -111,7 +126,7 @@ function failure(thrown: mixed): Outcome {
111
126
  stack,
112
127
  expected: thrown.expected,
113
128
  received: thrown.received,
114
- site: firstUserSite(stack, false),
129
+ site: siteOf(stack, file),
115
130
  };
116
131
  }
117
132
  if (thrown instanceof Error) {
@@ -122,7 +137,7 @@ function failure(thrown: mixed): Outcome {
122
137
  stack,
123
138
  expected: null,
124
139
  received: null,
125
- site: firstUserSite(stack, false),
140
+ site: siteOf(stack, file),
126
141
  };
127
142
  }
128
143
  return {
@@ -209,7 +224,7 @@ async function runCase(
209
224
  }
210
225
  await withTimeout(test.body, timeoutMs);
211
226
  } catch (thrown) {
212
- outcome = failure(thrown);
227
+ outcome = failure(thrown, options.file ?? null);
213
228
  }
214
229
  // Teardown runs whatever happened above, and only reports its own failure
215
230
  // when the body had not already failed.
@@ -218,7 +233,7 @@ async function runCase(
218
233
  await withTimeout(hook, timeoutMs);
219
234
  } catch (thrown) {
220
235
  if (outcome.status === "passed") {
221
- outcome = failure(thrown);
236
+ outcome = failure(thrown, options.file ?? null);
222
237
  }
223
238
  }
224
239
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniflowed/test",
3
- "version": "0.0.0-alpha.6",
3
+ "version": "0.0.0-alpha.7",
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",
@@ -21,6 +21,6 @@
21
21
  "internal"
22
22
  ],
23
23
  "dependencies": {
24
- "@uniflowed/host": "0.0.0-alpha.6"
24
+ "@uniflowed/host": "0.0.0-alpha.7"
25
25
  }
26
26
  }