@jterrazz/test 15.2.0 → 16.0.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.
package/dist/ambiguity.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/specification/facets/website/ambiguity.ts
1
+ //#region src/model/elements/ambiguity.ts
2
2
  /**
3
3
  * The ambiguity refusal — CONVENTIONS W3.
4
4
  *
@@ -52,8 +52,9 @@ const CONTEXT_LANDMARKS = {
52
52
  };
53
53
  /**
54
54
  * Render a descriptor as the source that would build it — `link('Articles')`,
55
- * `within(navigation(), link('Articles', { exact: true }))`. The error speaks
56
- * the vocabulary the author wrote, never playwright's.
55
+ * `within(navigation(), link('Articles', { exact: false }))`. The error speaks
56
+ * the vocabulary the author wrote, never playwright's — so the option appears
57
+ * only when the AUTHOR stated one, whichever way.
57
58
  */
58
59
  function formatElement(element) {
59
60
  const bare = formatBare(element);
@@ -62,7 +63,7 @@ function formatElement(element) {
62
63
  function formatBare(element) {
63
64
  const args = [];
64
65
  if (element.name !== void 0) args.push(JSON.stringify(element.name));
65
- if (element.exact) args.push("{ exact: true }");
66
+ if (element.exact !== void 0) args.push(`{ exact: ${String(element.exact)} }`);
66
67
  return `${CONSTRUCTORS[element.kind]}(${args.join(", ")})`;
67
68
  }
68
69
  /** `1. <a href="/articles">Articles</a> in <nav>` — one evidence line per candidate. */
@@ -98,7 +99,7 @@ function formatFixes(element, matches) {
98
99
  const alsoHere = rest.length > 0 ? ` [also here: ${rest.map(([name]) => name).join(", ")}]` : "";
99
100
  fixes.push(first === void 0 ? `scope it within(<a container holding only this one>, ${formatBare(element)})` : `scope it within(${first[0]}, ${formatBare(element)}) [leaves ${first[1]} of ${matches.length}]${alsoHere}`);
100
101
  }
101
- if (!element.exact && element.name !== void 0) {
102
+ if (element.exact === false && element.name !== void 0) {
102
103
  const remaining = matches.filter((match) => match.text === element.name).length;
103
104
  if (remaining > 0 && remaining < matches.length) fixes.push(`exact name ${formatBare({
104
105
  ...element,
@@ -138,7 +139,7 @@ function describeAmbiguity(options) {
138
139
  "Disambiguate with one of:",
139
140
  ...fixes,
140
141
  "",
141
- "Docs: docs/14-website.md#designating-exactly-one-element (CONVENTIONS W3)"
142
+ "Docs: docs/13-elements.md#designating-exactly-one-element (CONVENTIONS W3)"
142
143
  ].join("\n");
143
144
  }
144
145
  //#endregion
@@ -2,7 +2,7 @@ import { r as formatElement, t as AmbiguousElementError } from "./ambiguity.js";
2
2
  import { mkdtempSync, writeFileSync } from "node:fs";
3
3
  import { resolve } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
- //#region src/specification/facets/mobile/ambiguity.ts
5
+ //#region src/facets/mobile/ambiguity.ts
6
6
  /**
7
7
  * The ambiguity refusal, mobile edition — CONVENTIONS W3.
8
8
  *
@@ -28,15 +28,15 @@ function formatMatch(match, index) {
28
28
  }
29
29
  /**
30
30
  * The rewrites worth offering, in the order they should be tried. Scoping is
31
- * always available; `exact` only when it would actually narrow the set, and
32
- * the count it would leave is stated so a still-ambiguous suggestion never
33
- * reads as a fix; distinct identifiers make `testId()` a concrete rewrite
34
- * rather than a guess.
31
+ * always available; `exact` only to a descriptor that opted OUT of it (exact
32
+ * is the default), and the count it would leave is stated so a
33
+ * still-ambiguous suggestion never reads as a fix; distinct identifiers make
34
+ * `testId()` a concrete rewrite rather than a guess.
35
35
  */
36
36
  function formatFixes(element, matches) {
37
37
  const fixes = [];
38
38
  if (!element.scope) fixes.push(`scope it within(testId('…'), ${formatElement(element)}) — a screen has no landmarks; any descriptor works as the scope`);
39
- if (!element.exact && element.name !== void 0) {
39
+ if (element.exact === false && element.name !== void 0) {
40
40
  const remaining = matches.filter((match) => match.label === element.name).length;
41
41
  if (remaining > 0 && remaining < matches.length) fixes.push(`exact name ${formatElement({
42
42
  exact: true,
@@ -71,11 +71,11 @@ function describeMobileAmbiguity(options) {
71
71
  "Disambiguate with one of:",
72
72
  ...fixes,
73
73
  "",
74
- "Docs: docs/15-mobile.md#designating-exactly-one-element (CONVENTIONS W3)"
74
+ "Docs: docs/13-elements.md#designating-exactly-one-element (CONVENTIONS W3)"
75
75
  ].join("\n");
76
76
  }
77
77
  //#endregion
78
- //#region src/specification/facets/mobile/projection.ts
78
+ //#region src/facets/mobile/projection.ts
79
79
  const TAG_PATTERN = /<(?<openTag>[A-Za-z][\w.]*)(?<rawAttributes>(?:\s+[\w:.-]+="[^"]*")*)\s*(?<selfClosing>\/?)>|<\/(?<closeTag>[\w.]*)\s*>/gu;
80
80
  const ATTRIBUTE_PATTERN = /(?<key>[\w:.-]+)="(?<value>[^"]*)"/gu;
81
81
  const NAMED_ENTITIES = {
@@ -180,7 +180,7 @@ function projectScreen(xml) {
180
180
  };
181
181
  }
182
182
  //#endregion
183
- //#region src/integrations/appium/appium.adapter.ts
183
+ //#region src/seams/appium/appium.adapter.ts
184
184
  const DEFAULT_ACTION_TIMEOUT_MS = 3e4;
185
185
  const POLL_INTERVAL_MS = 500;
186
186
  /** How many candidates the ambiguity error enumerates before truncating. */
@@ -201,7 +201,7 @@ function escapePredicate(value) {
201
201
  */
202
202
  function compilePredicate(element, options) {
203
203
  const name = escapePredicate(element.name ?? "");
204
- const contains = (attribute) => element.exact ? `${attribute} == '${name}'` : `${attribute} CONTAINS '${name}'`;
204
+ const contains = (attribute) => element.exact === false ? `${attribute} CONTAINS '${name}'` : `${attribute} == '${name}'`;
205
205
  const visible = options?.anyVisibility ? "1 == 1" : "visible == 1";
206
206
  switch (element.kind) {
207
207
  case "button": return `type == 'XCUIElementTypeButton' AND ${contains("label")} AND ${visible}`;
@@ -391,7 +391,8 @@ var AppiumAdapter = class {
391
391
  /** Screenshot the failing state into a temp file; never masks the original error. */
392
392
  async captureEvidence(driver) {
393
393
  try {
394
- const path = resolve(mkdtempSync(resolve(tmpdir(), "spec-mobile-")), "failure.png");
394
+ const dir = mkdtempSync(resolve(tmpdir(), "spec-mobile-"));
395
+ const path = resolve(dir, "failure.png");
395
396
  writeFileSync(path, Buffer.from(await driver.takeScreenshot(), "base64"));
396
397
  return path;
397
398
  } catch {