@jterrazz/test 15.3.0 → 16.1.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.
Files changed (222) hide show
  1. package/README.md +120 -427
  2. package/dist/appium.adapter.js +71 -15
  3. package/dist/artifacts.js +25 -1735
  4. package/dist/browser/index.js +304 -233
  5. package/dist/checker.d.ts +1 -1
  6. package/dist/checker.js +1103 -97
  7. package/dist/fixtures.js +110 -0
  8. package/dist/index.d.ts +956 -971
  9. package/dist/index.js +2159 -2281
  10. package/dist/literate.js +1747 -0
  11. package/dist/match.js +625 -84
  12. package/dist/oxlint.cjs +3585 -1480
  13. package/dist/oxlint.d.cts +60 -48
  14. package/dist/oxlint.d.ts +60 -48
  15. package/dist/oxlint.js +3585 -1480
  16. package/dist/playwright.adapter.js +51 -8
  17. package/dist/{intercept.js → server.js} +2 -2
  18. package/dist/stream.js +6 -6
  19. package/dist/{ambiguity.js → substring-warning.js} +106 -7
  20. package/dist/vitest.d.ts +67 -48
  21. package/dist/vitest.js +229 -93
  22. package/docs/01-architecture.md +95 -0
  23. package/docs/02-developing.md +351 -0
  24. package/docs/03-testing.md +495 -0
  25. package/docs/04-operating.md +101 -0
  26. package/docs/05-module-tests.md +152 -0
  27. package/docs/06-integration.md +180 -0
  28. package/docs/07-component.md +246 -0
  29. package/docs/08-website.md +404 -0
  30. package/docs/09-mobile.md +270 -0
  31. package/docs/10-api.md +264 -0
  32. package/docs/11-jobs.md +157 -0
  33. package/docs/12-cli.md +677 -0
  34. package/docs/13-elements.md +242 -0
  35. package/docs/14-assertions.md +314 -0
  36. package/docs/15-tokens.md +253 -0
  37. package/docs/16-contracts.md +438 -0
  38. package/docs/17-services.md +188 -0
  39. package/docs/18-conventions.md +305 -0
  40. package/docs/19-linting.md +510 -0
  41. package/docs/README.md +36 -0
  42. package/docs/decisions/001-v9-conventions-on-three-channels.md +50 -0
  43. package/docs/decisions/002-the-statique-channel-holds-only-what-upstream-does-not.md +49 -0
  44. package/docs/decisions/003-a-rendered-component-is-a-facet-on-vitest-browser-mode.md +84 -0
  45. package/docs/decisions/004-a-module-against-real-services-or-a-golden-is-the-integration-facet.md +81 -0
  46. package/docs/decisions/005-the-doubles-ladder-is-closed.md +86 -0
  47. package/docs/decisions/006-the-catalogue-reaches-a-file-by-its-role.md +245 -0
  48. package/docs/decisions/007-compose-mode-leaves-the-package.md +53 -0
  49. package/docs/decisions/008-vitest-5-node-24-and-the-native-seams-as-optional-peers.md +75 -0
  50. package/docs/decisions/_template.md +22 -0
  51. package/docs/reference/classes/Matcher.md +120 -0
  52. package/docs/reference/classes/ProcessHandle.md +368 -0
  53. package/docs/reference/functions/defineContract.md +39 -0
  54. package/docs/reference/functions/defineContracts.md +36 -0
  55. package/docs/reference/functions/disabled.md +28 -0
  56. package/docs/reference/functions/enabled.md +20 -0
  57. package/docs/reference/functions/focused.md +26 -0
  58. package/docs/reference/functions/mockOf.md +79 -0
  59. package/docs/reference/functions/postgres.md +31 -0
  60. package/docs/reference/functions/process.md +33 -0
  61. package/docs/reference/functions/redis.md +28 -0
  62. package/docs/reference/functions/required.md +41 -0
  63. package/docs/reference/functions/selected.md +26 -0
  64. package/docs/reference/functions/sqlite.md +33 -0
  65. package/docs/reference/functions/testId.md +20 -0
  66. package/docs/reference/functions/text.md +40 -0
  67. package/docs/reference/functions/valued.md +28 -0
  68. package/docs/reference/functions/waitUntil.md +46 -0
  69. package/docs/reference/functions/within.md +29 -0
  70. package/docs/reference/index.md +196 -0
  71. package/docs/reference/interfaces/BaseResult.md +87 -0
  72. package/docs/reference/interfaces/CallResult.md +160 -0
  73. package/docs/reference/interfaces/CaptureScope.md +82 -0
  74. package/docs/reference/interfaces/CliResult.md +253 -0
  75. package/docs/reference/interfaces/ContainerAccessor.md +166 -0
  76. package/docs/reference/interfaces/DirectoryAccessor.md +33 -0
  77. package/docs/reference/interfaces/FetchResult.md +180 -0
  78. package/docs/reference/interfaces/FilesystemAccessor.md +46 -0
  79. package/docs/reference/interfaces/HttpResult.md +126 -0
  80. package/docs/reference/interfaces/JsonAccessor.md +46 -0
  81. package/docs/reference/interfaces/PageResult.md +356 -0
  82. package/docs/reference/interfaces/RenderResult.md +72 -0
  83. package/docs/reference/interfaces/RenderedText.md +110 -0
  84. package/docs/reference/interfaces/ResponseAccessor.md +47 -0
  85. package/docs/reference/interfaces/ScreenResult.md +128 -0
  86. package/docs/reference/interfaces/TableAccessor.md +26 -0
  87. package/docs/reference/interfaces/TextAccessor.md +96 -0
  88. package/docs/reference/type-aliases/ApiHandle.md +68 -0
  89. package/docs/reference/type-aliases/ApiSpecification.md +213 -0
  90. package/docs/reference/type-aliases/ApiSpecificationOptions.md +68 -0
  91. package/docs/reference/type-aliases/BrowserConsoleMessage.md +30 -0
  92. package/docs/reference/type-aliases/BrowserLinkElement.md +50 -0
  93. package/docs/reference/type-aliases/BrowserMetaElement.md +40 -0
  94. package/docs/reference/type-aliases/BrowserOpenOptions.md +87 -0
  95. package/docs/reference/type-aliases/BrowserPage.md +132 -0
  96. package/docs/reference/type-aliases/BrowserPort.md +51 -0
  97. package/docs/reference/type-aliases/CliEnv.md +11 -0
  98. package/docs/reference/type-aliases/CliHandle.md +80 -0
  99. package/docs/reference/type-aliases/CliInput.md +36 -0
  100. package/docs/reference/type-aliases/CliOutput.md +46 -0
  101. package/docs/reference/type-aliases/CliPort.md +58 -0
  102. package/docs/reference/type-aliases/CliSpecification.md +144 -0
  103. package/docs/reference/type-aliases/CliSpecificationOptions.md +134 -0
  104. package/docs/reference/type-aliases/ComponentChain.md +156 -0
  105. package/docs/reference/type-aliases/ComponentScenario.md +20 -0
  106. package/docs/reference/type-aliases/ComponentUi.md +47 -0
  107. package/docs/reference/type-aliases/ComponentVisitor.md +10 -0
  108. package/docs/reference/type-aliases/ContainerPort.md +113 -0
  109. package/docs/reference/type-aliases/Contract.md +68 -0
  110. package/docs/reference/type-aliases/ContractInput.md +13 -0
  111. package/docs/reference/type-aliases/ContractRequest.md +95 -0
  112. package/docs/reference/type-aliases/ContractResponder.md +23 -0
  113. package/docs/reference/type-aliases/ContractResponse.md +78 -0
  114. package/docs/reference/type-aliases/ContractResponseValue.md +13 -0
  115. package/docs/reference/type-aliases/Contracts.md +48 -0
  116. package/docs/reference/type-aliases/DatabaseKeys.md +16 -0
  117. package/docs/reference/type-aliases/DatabasePort.md +72 -0
  118. package/docs/reference/type-aliases/DeviceOpenOptions.md +46 -0
  119. package/docs/reference/type-aliases/DevicePort.md +51 -0
  120. package/docs/reference/type-aliases/DeviceScreen.md +32 -0
  121. package/docs/reference/type-aliases/DeviceTimeouts.md +39 -0
  122. package/docs/reference/type-aliases/DockerSpecConfig.md +43 -0
  123. package/docs/reference/type-aliases/DomMount.md +21 -0
  124. package/docs/reference/type-aliases/ElementKind.md +27 -0
  125. package/docs/reference/type-aliases/ElementMatch.md +74 -0
  126. package/docs/reference/type-aliases/ElementOptions.md +29 -0
  127. package/docs/reference/type-aliases/ElementRef.md +128 -0
  128. package/docs/reference/type-aliases/ExecOptions.md +37 -0
  129. package/docs/reference/type-aliases/FileAccessor.md +54 -0
  130. package/docs/reference/type-aliases/HonoApp.md +31 -0
  131. package/docs/reference/type-aliases/HttpContractFilter.md +49 -0
  132. package/docs/reference/type-aliases/HttpResponseInit.md +46 -0
  133. package/docs/reference/type-aliases/HttpStreamInit.md +58 -0
  134. package/docs/reference/type-aliases/IntegrationHandle.md +46 -0
  135. package/docs/reference/type-aliases/IntegrationSpecification.md +111 -0
  136. package/docs/reference/type-aliases/IntegrationSpecificationOptions.md +42 -0
  137. package/docs/reference/type-aliases/Intercept.md +19 -0
  138. package/docs/reference/type-aliases/InterceptOptions.md +28 -0
  139. package/docs/reference/type-aliases/InterceptScope.md +11 -0
  140. package/docs/reference/type-aliases/IsolationStrategy.md +75 -0
  141. package/docs/reference/type-aliases/JobHandle.md +34 -0
  142. package/docs/reference/type-aliases/JobsHandle.md +57 -0
  143. package/docs/reference/type-aliases/JobsResult.md +16 -0
  144. package/docs/reference/type-aliases/JobsSpecification.md +94 -0
  145. package/docs/reference/type-aliases/JobsSpecificationOptions.md +56 -0
  146. package/docs/reference/type-aliases/LandmarkKind.md +20 -0
  147. package/docs/reference/type-aliases/LiterateRunFlags.md +27 -0
  148. package/docs/reference/type-aliases/LiterateServeRegistration.md +70 -0
  149. package/docs/reference/type-aliases/MatchFixtureOptions.md +27 -0
  150. package/docs/reference/type-aliases/MatchableRequest.md +61 -0
  151. package/docs/reference/type-aliases/MatcherKind.md +34 -0
  152. package/docs/reference/type-aliases/MobileBackendOptions.md +28 -0
  153. package/docs/reference/type-aliases/MobileElementKind.md +14 -0
  154. package/docs/reference/type-aliases/MobileElementMatch.md +60 -0
  155. package/docs/reference/type-aliases/MobileElementRef.md +20 -0
  156. package/docs/reference/type-aliases/MobileHandle.md +65 -0
  157. package/docs/reference/type-aliases/MobileScenario.md +20 -0
  158. package/docs/reference/type-aliases/MobileSpecification.md +51 -0
  159. package/docs/reference/type-aliases/MobileSpecificationOptions.md +126 -0
  160. package/docs/reference/type-aliases/MobileVisitor.md +81 -0
  161. package/docs/reference/type-aliases/MockOfOptions.md +26 -0
  162. package/docs/reference/type-aliases/MockPort.md +10 -0
  163. package/docs/reference/type-aliases/PinnedClock.md +10 -0
  164. package/docs/reference/type-aliases/PostgresOptions.md +32 -0
  165. package/docs/reference/type-aliases/ProcessOptions.md +112 -0
  166. package/docs/reference/type-aliases/RedisOptions.md +20 -0
  167. package/docs/reference/type-aliases/RenderSubject.md +12 -0
  168. package/docs/reference/type-aliases/ScreenNode.md +67 -0
  169. package/docs/reference/type-aliases/ServerPort.md +36 -0
  170. package/docs/reference/type-aliases/ServerResponse.md +46 -0
  171. package/docs/reference/type-aliases/ServerSpec.md +21 -0
  172. package/docs/reference/type-aliases/ServiceHandle.md +216 -0
  173. package/docs/reference/type-aliases/ServiceRecord.md +12 -0
  174. package/docs/reference/type-aliases/SpecDocument.md +84 -0
  175. package/docs/reference/type-aliases/SpecEnvToken.md +21 -0
  176. package/docs/reference/type-aliases/SpecFileAssertion.md +27 -0
  177. package/docs/reference/type-aliases/SpecFixture.md +30 -0
  178. package/docs/reference/type-aliases/SpecKind.md +8 -0
  179. package/docs/reference/type-aliases/SpecRun.md +108 -0
  180. package/docs/reference/type-aliases/SpecServeEntry.md +40 -0
  181. package/docs/reference/type-aliases/SpecStream.md +32 -0
  182. package/docs/reference/type-aliases/SpecificationConfig.md +290 -0
  183. package/docs/reference/type-aliases/SqliteOptions.md +36 -0
  184. package/docs/reference/type-aliases/SseEvent.md +58 -0
  185. package/docs/reference/type-aliases/StreamBody.md +61 -0
  186. package/docs/reference/type-aliases/TextFilter.md +22 -0
  187. package/docs/reference/type-aliases/VisitScenario.md +20 -0
  188. package/docs/reference/type-aliases/Visitor.md +215 -0
  189. package/docs/reference/type-aliases/WaitUntilOptions.md +46 -0
  190. package/docs/reference/type-aliases/WebsiteBackendOptions.md +37 -0
  191. package/docs/reference/type-aliases/WebsiteHandle.md +51 -0
  192. package/docs/reference/type-aliases/WebsiteSpecification.md +118 -0
  193. package/docs/reference/type-aliases/WebsiteSpecificationOptions.md +40 -0
  194. package/docs/reference/variables/anthropic.md +19 -0
  195. package/docs/reference/variables/banner.md +10 -0
  196. package/docs/reference/variables/button.md +10 -0
  197. package/docs/reference/variables/clock.md +16 -0
  198. package/docs/reference/variables/complementary.md +10 -0
  199. package/docs/reference/variables/component.md +10 -0
  200. package/docs/reference/variables/content.md +10 -0
  201. package/docs/reference/variables/contentinfo.md +10 -0
  202. package/docs/reference/variables/dialog.md +10 -0
  203. package/docs/reference/variables/field.md +10 -0
  204. package/docs/reference/variables/form.md +10 -0
  205. package/docs/reference/variables/heading.md +10 -0
  206. package/docs/reference/variables/http.md +40 -0
  207. package/docs/reference/variables/intercept.md +11 -0
  208. package/docs/reference/variables/link.md +10 -0
  209. package/docs/reference/variables/listitem.md +10 -0
  210. package/docs/reference/variables/main.md +10 -0
  211. package/docs/reference/variables/match.md +8 -0
  212. package/docs/reference/variables/navigation.md +10 -0
  213. package/docs/reference/variables/openai.md +21 -0
  214. package/docs/reference/variables/option.md +17 -0
  215. package/docs/reference/variables/region.md +10 -0
  216. package/docs/reference/variables/row.md +10 -0
  217. package/docs/reference/variables/search.md +10 -0
  218. package/docs/reference/variables/specification.md +8 -0
  219. package/docs/reference/variables/status.md +10 -0
  220. package/docs/reference/variables/table.md +10 -0
  221. package/package.json +32 -11
  222. package/dist/spec-document.js +0 -651
@@ -1,8 +1,8 @@
1
- import { r as formatElement, t as AmbiguousElementError } from "./ambiguity.js";
1
+ import { a as formatElement, r as AmbiguousElementError, t as warnSubstringOnly } from "./substring-warning.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}`;
@@ -211,6 +211,16 @@ function compilePredicate(element, options) {
211
211
  default: throw new Error(`${formatElement(element)}: landmarks are a website concept — an iOS screen has no '${element.kind}' region. Scope with within(testId('…'), …) instead.`);
212
212
  }
213
213
  }
214
+ /**
215
+ * Every element a predicate designates under `scope`.
216
+ *
217
+ * ONE place awaits webdriverio's query: `$$` answers a chainable typed as the
218
+ * array it resolves to, so the await that makes the array real reads to the
219
+ * typechecker as an await of a non-promise.
220
+ */
221
+ async function matching(scope, element, options) {
222
+ return await scope.$$(`-ios predicate string:${compilePredicate(element, options)}`);
223
+ }
214
224
  /** The outside-in scope chain of a descriptor, ending on the target itself. */
215
225
  function scopeChain(element) {
216
226
  const chain = [];
@@ -341,10 +351,16 @@ var AppiumAdapter = class {
341
351
  const chain = scopeChain(element);
342
352
  const deadline = Date.now() + this.actionTimeoutMs;
343
353
  let scrollAttempted = false;
354
+ let windowAsked = false;
355
+ let looking = chain;
344
356
  for (;;) {
345
- const resolved = await this.resolveChain(driver, chain, cardinality, { tryScroll: !scrollAttempted });
357
+ const resolved = await this.resolveChain(driver, looking, cardinality, { tryScroll: !scrollAttempted });
346
358
  scrollAttempted = true;
347
359
  if (resolved) return resolved;
360
+ if (!windowAsked) {
361
+ windowAsked = true;
362
+ looking = await this.widenedChain(driver, chain) ?? chain;
363
+ }
348
364
  if (Date.now() > deadline) throw await this.timeoutError(driver, element, verb);
349
365
  await delay(POLL_INTERVAL_MS);
350
366
  }
@@ -353,11 +369,11 @@ var AppiumAdapter = class {
353
369
  async resolveChain(driver, chain, cardinality, options) {
354
370
  let scope = driver;
355
371
  for (const [index, level] of chain.entries()) {
356
- const matches = await scope.$$(`-ios predicate string:${compilePredicate(level)}`);
372
+ const matches = await matching(scope, level);
357
373
  const count = await matches.length;
358
374
  if (count === 0) {
359
375
  if (options?.tryScroll) {
360
- const first = (await scope.$$(`-ios predicate string:${compilePredicate(level, { anyVisibility: true })}`))[0];
376
+ const first = (await matching(scope, level, { anyVisibility: true }))[0];
361
377
  if (first !== void 0) try {
362
378
  await driver.executeScript("mobile: scroll", [{
363
379
  elementId: first.elementId,
@@ -378,6 +394,45 @@ var AppiumAdapter = class {
378
394
  }
379
395
  return scope;
380
396
  }
397
+ /**
398
+ * The chain to keep polling with, level by level: a descriptor that
399
+ * designated nothing as a whole label but designates exactly one thing as a
400
+ * SUBSTRING is widened, with the warning that names the label to write. The
401
+ * window is the vocabulary's, not one surface's — chapter 13 — so the
402
+ * screen answers it exactly as a page does.
403
+ *
404
+ * `null` when nothing would change, which is the ordinary wait.
405
+ */
406
+ async widenedChain(driver, chain) {
407
+ let scope = driver;
408
+ const widened = [];
409
+ let changed = false;
410
+ for (const level of chain) {
411
+ const found = await this.widenedLevel(scope, level);
412
+ changed ||= found !== null;
413
+ const candidate = found ?? level;
414
+ const next = (await matching(scope, candidate))[0];
415
+ if (next === void 0) return null;
416
+ scope = next;
417
+ widened.push(candidate);
418
+ }
419
+ return changed ? widened : null;
420
+ }
421
+ /** One level of the chain, widened and warned about, or `null`. */
422
+ async widenedLevel(scope, level) {
423
+ if (level.exact !== void 0 || level.name === void 0) return null;
424
+ if (await (await matching(scope, level)).length > 0) return null;
425
+ const loose = {
426
+ ...level,
427
+ exact: false
428
+ };
429
+ const matches = await matching(scope, loose);
430
+ const first = matches[0];
431
+ if (first === void 0 || await matches.length !== 1) return null;
432
+ const evidence = await captureMatch(first);
433
+ warnSubstringOnly(level, this.options.udid, evidence.label);
434
+ return loose;
435
+ }
381
436
  /** Enumerate the candidates' evidence, truncated. */
382
437
  async captureMatches(matches) {
383
438
  const count = Math.min(await matches.length, MAX_REPORTED_MATCHES);
@@ -391,7 +446,8 @@ var AppiumAdapter = class {
391
446
  /** Screenshot the failing state into a temp file; never masks the original error. */
392
447
  async captureEvidence(driver) {
393
448
  try {
394
- const path = resolve(mkdtempSync(resolve(tmpdir(), "spec-mobile-")), "failure.png");
449
+ const dir = mkdtempSync(resolve(tmpdir(), "spec-mobile-"));
450
+ const path = resolve(dir, "failure.png");
395
451
  writeFileSync(path, Buffer.from(await driver.takeScreenshot(), "base64"));
396
452
  return path;
397
453
  } catch {