@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.
- package/README.md +120 -427
- package/dist/appium.adapter.js +71 -15
- package/dist/artifacts.js +25 -1735
- package/dist/browser/index.js +304 -233
- package/dist/checker.d.ts +1 -1
- package/dist/checker.js +1103 -97
- package/dist/fixtures.js +110 -0
- package/dist/index.d.ts +956 -971
- package/dist/index.js +2159 -2281
- package/dist/literate.js +1747 -0
- package/dist/match.js +625 -84
- package/dist/oxlint.cjs +3585 -1480
- package/dist/oxlint.d.cts +60 -48
- package/dist/oxlint.d.ts +60 -48
- package/dist/oxlint.js +3585 -1480
- package/dist/playwright.adapter.js +51 -8
- package/dist/{intercept.js → server.js} +2 -2
- package/dist/stream.js +6 -6
- package/dist/{ambiguity.js → substring-warning.js} +106 -7
- package/dist/vitest.d.ts +67 -48
- package/dist/vitest.js +229 -93
- package/docs/01-architecture.md +95 -0
- package/docs/02-developing.md +351 -0
- package/docs/03-testing.md +495 -0
- package/docs/04-operating.md +101 -0
- package/docs/05-module-tests.md +152 -0
- package/docs/06-integration.md +180 -0
- package/docs/07-component.md +246 -0
- package/docs/08-website.md +404 -0
- package/docs/09-mobile.md +270 -0
- package/docs/10-api.md +264 -0
- package/docs/11-jobs.md +157 -0
- package/docs/12-cli.md +677 -0
- package/docs/13-elements.md +242 -0
- package/docs/14-assertions.md +314 -0
- package/docs/15-tokens.md +253 -0
- package/docs/16-contracts.md +438 -0
- package/docs/17-services.md +188 -0
- package/docs/18-conventions.md +305 -0
- package/docs/19-linting.md +510 -0
- package/docs/README.md +36 -0
- package/docs/decisions/001-v9-conventions-on-three-channels.md +50 -0
- package/docs/decisions/002-the-statique-channel-holds-only-what-upstream-does-not.md +49 -0
- package/docs/decisions/003-a-rendered-component-is-a-facet-on-vitest-browser-mode.md +84 -0
- package/docs/decisions/004-a-module-against-real-services-or-a-golden-is-the-integration-facet.md +81 -0
- package/docs/decisions/005-the-doubles-ladder-is-closed.md +86 -0
- package/docs/decisions/006-the-catalogue-reaches-a-file-by-its-role.md +245 -0
- package/docs/decisions/007-compose-mode-leaves-the-package.md +53 -0
- package/docs/decisions/008-vitest-5-node-24-and-the-native-seams-as-optional-peers.md +75 -0
- package/docs/decisions/_template.md +22 -0
- package/docs/reference/classes/Matcher.md +120 -0
- package/docs/reference/classes/ProcessHandle.md +368 -0
- package/docs/reference/functions/defineContract.md +39 -0
- package/docs/reference/functions/defineContracts.md +36 -0
- package/docs/reference/functions/disabled.md +28 -0
- package/docs/reference/functions/enabled.md +20 -0
- package/docs/reference/functions/focused.md +26 -0
- package/docs/reference/functions/mockOf.md +79 -0
- package/docs/reference/functions/postgres.md +31 -0
- package/docs/reference/functions/process.md +33 -0
- package/docs/reference/functions/redis.md +28 -0
- package/docs/reference/functions/required.md +41 -0
- package/docs/reference/functions/selected.md +26 -0
- package/docs/reference/functions/sqlite.md +33 -0
- package/docs/reference/functions/testId.md +20 -0
- package/docs/reference/functions/text.md +40 -0
- package/docs/reference/functions/valued.md +28 -0
- package/docs/reference/functions/waitUntil.md +46 -0
- package/docs/reference/functions/within.md +29 -0
- package/docs/reference/index.md +196 -0
- package/docs/reference/interfaces/BaseResult.md +87 -0
- package/docs/reference/interfaces/CallResult.md +160 -0
- package/docs/reference/interfaces/CaptureScope.md +82 -0
- package/docs/reference/interfaces/CliResult.md +253 -0
- package/docs/reference/interfaces/ContainerAccessor.md +166 -0
- package/docs/reference/interfaces/DirectoryAccessor.md +33 -0
- package/docs/reference/interfaces/FetchResult.md +180 -0
- package/docs/reference/interfaces/FilesystemAccessor.md +46 -0
- package/docs/reference/interfaces/HttpResult.md +126 -0
- package/docs/reference/interfaces/JsonAccessor.md +46 -0
- package/docs/reference/interfaces/PageResult.md +356 -0
- package/docs/reference/interfaces/RenderResult.md +72 -0
- package/docs/reference/interfaces/RenderedText.md +110 -0
- package/docs/reference/interfaces/ResponseAccessor.md +47 -0
- package/docs/reference/interfaces/ScreenResult.md +128 -0
- package/docs/reference/interfaces/TableAccessor.md +26 -0
- package/docs/reference/interfaces/TextAccessor.md +96 -0
- package/docs/reference/type-aliases/ApiHandle.md +68 -0
- package/docs/reference/type-aliases/ApiSpecification.md +213 -0
- package/docs/reference/type-aliases/ApiSpecificationOptions.md +68 -0
- package/docs/reference/type-aliases/BrowserConsoleMessage.md +30 -0
- package/docs/reference/type-aliases/BrowserLinkElement.md +50 -0
- package/docs/reference/type-aliases/BrowserMetaElement.md +40 -0
- package/docs/reference/type-aliases/BrowserOpenOptions.md +87 -0
- package/docs/reference/type-aliases/BrowserPage.md +132 -0
- package/docs/reference/type-aliases/BrowserPort.md +51 -0
- package/docs/reference/type-aliases/CliEnv.md +11 -0
- package/docs/reference/type-aliases/CliHandle.md +80 -0
- package/docs/reference/type-aliases/CliInput.md +36 -0
- package/docs/reference/type-aliases/CliOutput.md +46 -0
- package/docs/reference/type-aliases/CliPort.md +58 -0
- package/docs/reference/type-aliases/CliSpecification.md +144 -0
- package/docs/reference/type-aliases/CliSpecificationOptions.md +134 -0
- package/docs/reference/type-aliases/ComponentChain.md +156 -0
- package/docs/reference/type-aliases/ComponentScenario.md +20 -0
- package/docs/reference/type-aliases/ComponentUi.md +47 -0
- package/docs/reference/type-aliases/ComponentVisitor.md +10 -0
- package/docs/reference/type-aliases/ContainerPort.md +113 -0
- package/docs/reference/type-aliases/Contract.md +68 -0
- package/docs/reference/type-aliases/ContractInput.md +13 -0
- package/docs/reference/type-aliases/ContractRequest.md +95 -0
- package/docs/reference/type-aliases/ContractResponder.md +23 -0
- package/docs/reference/type-aliases/ContractResponse.md +78 -0
- package/docs/reference/type-aliases/ContractResponseValue.md +13 -0
- package/docs/reference/type-aliases/Contracts.md +48 -0
- package/docs/reference/type-aliases/DatabaseKeys.md +16 -0
- package/docs/reference/type-aliases/DatabasePort.md +72 -0
- package/docs/reference/type-aliases/DeviceOpenOptions.md +46 -0
- package/docs/reference/type-aliases/DevicePort.md +51 -0
- package/docs/reference/type-aliases/DeviceScreen.md +32 -0
- package/docs/reference/type-aliases/DeviceTimeouts.md +39 -0
- package/docs/reference/type-aliases/DockerSpecConfig.md +43 -0
- package/docs/reference/type-aliases/DomMount.md +21 -0
- package/docs/reference/type-aliases/ElementKind.md +27 -0
- package/docs/reference/type-aliases/ElementMatch.md +74 -0
- package/docs/reference/type-aliases/ElementOptions.md +29 -0
- package/docs/reference/type-aliases/ElementRef.md +128 -0
- package/docs/reference/type-aliases/ExecOptions.md +37 -0
- package/docs/reference/type-aliases/FileAccessor.md +54 -0
- package/docs/reference/type-aliases/HonoApp.md +31 -0
- package/docs/reference/type-aliases/HttpContractFilter.md +49 -0
- package/docs/reference/type-aliases/HttpResponseInit.md +46 -0
- package/docs/reference/type-aliases/HttpStreamInit.md +58 -0
- package/docs/reference/type-aliases/IntegrationHandle.md +46 -0
- package/docs/reference/type-aliases/IntegrationSpecification.md +111 -0
- package/docs/reference/type-aliases/IntegrationSpecificationOptions.md +42 -0
- package/docs/reference/type-aliases/Intercept.md +19 -0
- package/docs/reference/type-aliases/InterceptOptions.md +28 -0
- package/docs/reference/type-aliases/InterceptScope.md +11 -0
- package/docs/reference/type-aliases/IsolationStrategy.md +75 -0
- package/docs/reference/type-aliases/JobHandle.md +34 -0
- package/docs/reference/type-aliases/JobsHandle.md +57 -0
- package/docs/reference/type-aliases/JobsResult.md +16 -0
- package/docs/reference/type-aliases/JobsSpecification.md +94 -0
- package/docs/reference/type-aliases/JobsSpecificationOptions.md +56 -0
- package/docs/reference/type-aliases/LandmarkKind.md +20 -0
- package/docs/reference/type-aliases/LiterateRunFlags.md +27 -0
- package/docs/reference/type-aliases/LiterateServeRegistration.md +70 -0
- package/docs/reference/type-aliases/MatchFixtureOptions.md +27 -0
- package/docs/reference/type-aliases/MatchableRequest.md +61 -0
- package/docs/reference/type-aliases/MatcherKind.md +34 -0
- package/docs/reference/type-aliases/MobileBackendOptions.md +28 -0
- package/docs/reference/type-aliases/MobileElementKind.md +14 -0
- package/docs/reference/type-aliases/MobileElementMatch.md +60 -0
- package/docs/reference/type-aliases/MobileElementRef.md +20 -0
- package/docs/reference/type-aliases/MobileHandle.md +65 -0
- package/docs/reference/type-aliases/MobileScenario.md +20 -0
- package/docs/reference/type-aliases/MobileSpecification.md +51 -0
- package/docs/reference/type-aliases/MobileSpecificationOptions.md +126 -0
- package/docs/reference/type-aliases/MobileVisitor.md +81 -0
- package/docs/reference/type-aliases/MockOfOptions.md +26 -0
- package/docs/reference/type-aliases/MockPort.md +10 -0
- package/docs/reference/type-aliases/PinnedClock.md +10 -0
- package/docs/reference/type-aliases/PostgresOptions.md +32 -0
- package/docs/reference/type-aliases/ProcessOptions.md +112 -0
- package/docs/reference/type-aliases/RedisOptions.md +20 -0
- package/docs/reference/type-aliases/RenderSubject.md +12 -0
- package/docs/reference/type-aliases/ScreenNode.md +67 -0
- package/docs/reference/type-aliases/ServerPort.md +36 -0
- package/docs/reference/type-aliases/ServerResponse.md +46 -0
- package/docs/reference/type-aliases/ServerSpec.md +21 -0
- package/docs/reference/type-aliases/ServiceHandle.md +216 -0
- package/docs/reference/type-aliases/ServiceRecord.md +12 -0
- package/docs/reference/type-aliases/SpecDocument.md +84 -0
- package/docs/reference/type-aliases/SpecEnvToken.md +21 -0
- package/docs/reference/type-aliases/SpecFileAssertion.md +27 -0
- package/docs/reference/type-aliases/SpecFixture.md +30 -0
- package/docs/reference/type-aliases/SpecKind.md +8 -0
- package/docs/reference/type-aliases/SpecRun.md +108 -0
- package/docs/reference/type-aliases/SpecServeEntry.md +40 -0
- package/docs/reference/type-aliases/SpecStream.md +32 -0
- package/docs/reference/type-aliases/SpecificationConfig.md +290 -0
- package/docs/reference/type-aliases/SqliteOptions.md +36 -0
- package/docs/reference/type-aliases/SseEvent.md +58 -0
- package/docs/reference/type-aliases/StreamBody.md +61 -0
- package/docs/reference/type-aliases/TextFilter.md +22 -0
- package/docs/reference/type-aliases/VisitScenario.md +20 -0
- package/docs/reference/type-aliases/Visitor.md +215 -0
- package/docs/reference/type-aliases/WaitUntilOptions.md +46 -0
- package/docs/reference/type-aliases/WebsiteBackendOptions.md +37 -0
- package/docs/reference/type-aliases/WebsiteHandle.md +51 -0
- package/docs/reference/type-aliases/WebsiteSpecification.md +118 -0
- package/docs/reference/type-aliases/WebsiteSpecificationOptions.md +40 -0
- package/docs/reference/variables/anthropic.md +19 -0
- package/docs/reference/variables/banner.md +10 -0
- package/docs/reference/variables/button.md +10 -0
- package/docs/reference/variables/clock.md +16 -0
- package/docs/reference/variables/complementary.md +10 -0
- package/docs/reference/variables/component.md +10 -0
- package/docs/reference/variables/content.md +10 -0
- package/docs/reference/variables/contentinfo.md +10 -0
- package/docs/reference/variables/dialog.md +10 -0
- package/docs/reference/variables/field.md +10 -0
- package/docs/reference/variables/form.md +10 -0
- package/docs/reference/variables/heading.md +10 -0
- package/docs/reference/variables/http.md +40 -0
- package/docs/reference/variables/intercept.md +11 -0
- package/docs/reference/variables/link.md +10 -0
- package/docs/reference/variables/listitem.md +10 -0
- package/docs/reference/variables/main.md +10 -0
- package/docs/reference/variables/match.md +8 -0
- package/docs/reference/variables/navigation.md +10 -0
- package/docs/reference/variables/openai.md +21 -0
- package/docs/reference/variables/option.md +17 -0
- package/docs/reference/variables/region.md +10 -0
- package/docs/reference/variables/row.md +10 -0
- package/docs/reference/variables/search.md +10 -0
- package/docs/reference/variables/specification.md +8 -0
- package/docs/reference/variables/status.md +10 -0
- package/docs/reference/variables/table.md +10 -0
- package/package.json +32 -11
- package/dist/spec-document.js +0 -651
package/dist/appium.adapter.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
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/
|
|
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
|
|
32
|
-
* the count it would leave is stated so a
|
|
33
|
-
* reads as a fix; distinct identifiers make
|
|
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 (
|
|
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/
|
|
74
|
+
"Docs: docs/13-elements.md#designating-exactly-one-element (CONVENTIONS W3)"
|
|
75
75
|
].join("\n");
|
|
76
76
|
}
|
|
77
77
|
//#endregion
|
|
78
|
-
//#region src/
|
|
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/
|
|
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}
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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 {
|