@qawolf/cli 1.7.1 → 1.7.3
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/cli.js +410 -272
- package/package.json +1 -2
package/dist/cli.js
CHANGED
|
@@ -8514,7 +8514,7 @@ var require_BufferList = __commonJS((exports, module) => {
|
|
|
8514
8514
|
this.head = this.tail = null;
|
|
8515
8515
|
this.length = 0;
|
|
8516
8516
|
};
|
|
8517
|
-
BufferList.prototype.join = function
|
|
8517
|
+
BufferList.prototype.join = function join35(s3) {
|
|
8518
8518
|
if (this.length === 0)
|
|
8519
8519
|
return "";
|
|
8520
8520
|
var p3 = this.head;
|
|
@@ -23070,7 +23070,7 @@ var require_BufferList2 = __commonJS((exports, module) => {
|
|
|
23070
23070
|
this.head = this.tail = null;
|
|
23071
23071
|
this.length = 0;
|
|
23072
23072
|
};
|
|
23073
|
-
BufferList.prototype.join = function
|
|
23073
|
+
BufferList.prototype.join = function join35(s3) {
|
|
23074
23074
|
if (this.length === 0)
|
|
23075
23075
|
return "";
|
|
23076
23076
|
var p3 = this.head;
|
|
@@ -155283,7 +155283,8 @@ var doctorMessages = {
|
|
|
155283
155283
|
playwright: {
|
|
155284
155284
|
notFound: (path) => toolNotInstalled("Playwright", path),
|
|
155285
155285
|
launchFailed: "Could not launch Playwright. Try reinstalling the qawolf CLI.",
|
|
155286
|
-
versionUnparseable: "Could not parse playwright version output"
|
|
155286
|
+
versionUnparseable: "Could not parse playwright version output",
|
|
155287
|
+
versionMismatch: (installed, pinned) => `Playwright ${installed} is installed but the flow runtime requires ${pinned}; local runs will fail to launch browsers. Run \`qawolf install\` to repair the runtime dependencies.`
|
|
155287
155288
|
},
|
|
155288
155289
|
appium: {
|
|
155289
155290
|
notFound: (path) => toolNotInstalled("Appium", path),
|
|
@@ -155313,6 +155314,8 @@ var environmentsMessages = {
|
|
|
155313
155314
|
static: "Static environments",
|
|
155314
155315
|
preview: "Preview (PR) environments"
|
|
155315
155316
|
},
|
|
155317
|
+
resolvedAlias: (ref, id) => `Environment ${ref} resolved to ${id}.`,
|
|
155318
|
+
couldNotResolve: (ref, detail) => `Could not resolve environment ${ref}: ${detail} If ${ref} is an alias, note that aliases require a team API key.`,
|
|
155316
155319
|
aborted: "Aborted; no environment selected.",
|
|
155317
155320
|
tooManyPages: (pages) => `Stopped listing environments after ${pages} pages. Pass --env explicitly.`
|
|
155318
155321
|
};
|
|
@@ -155330,6 +155333,9 @@ var flowsMessages = {
|
|
|
155330
155333
|
remoteRequiresEnv: "--remote requires an environment. Pass --env <env> or set QAWOLF_ENVIRONMENT.",
|
|
155331
155334
|
flagsRequireRemote: "--env and --include-drafts require --remote"
|
|
155332
155335
|
},
|
|
155336
|
+
run: {
|
|
155337
|
+
requiresEnv: "An environment is required. Pass --env <env> or set QAWOLF_ENVIRONMENT."
|
|
155338
|
+
},
|
|
155333
155339
|
pull: {
|
|
155334
155340
|
requiresEnv: "An environment is required. Pass --env <env> or set QAWOLF_ENVIRONMENT.",
|
|
155335
155341
|
downloadingBundle: "Downloading flows bundle",
|
|
@@ -155390,11 +155396,20 @@ var initMessages = {
|
|
|
155390
155396
|
outro: "Run `qawolf auth login`, then `qawolf flows pull`, then `qawolf flows run`.",
|
|
155391
155397
|
createPackageJsonPrompt: "Create package.json (required to run flows)?",
|
|
155392
155398
|
skippedCreatingPackageJson: "Skipped package.json",
|
|
155393
|
-
|
|
155399
|
+
skippedUpdatingPackageJson: "Skipped updating package.json",
|
|
155394
155400
|
createdPackageJson: "Created package.json",
|
|
155395
|
-
packageJsonInvalidJson: "package.json
|
|
155396
|
-
|
|
155397
|
-
|
|
155401
|
+
packageJsonInvalidJson: "`package.json` contains invalid JSON. Correct the JSON syntax, then run `qawolf init` again.",
|
|
155402
|
+
packageJsonNotAnObject: "`package.json` must contain a JSON object. Update it, then run `qawolf init` again.",
|
|
155403
|
+
packageJsonMalformedSection: (field) => `The \`${field}\` field in \`package.json\` must be a JSON object. Update it, then run \`qawolf init\` again.`,
|
|
155404
|
+
packageJsonHasTestE2e: "package.json already has `test:e2e` — leaving it as is",
|
|
155405
|
+
packageJsonUpToDate: "package.json already configured — nothing to update",
|
|
155406
|
+
typeChanged: (from) => `Changed "type" from "${from}" to "module" — .js files in this package now load as ES modules.`,
|
|
155407
|
+
pkgChanges: {
|
|
155408
|
+
script: "add `test:e2e` script",
|
|
155409
|
+
type: 'set "type": "module"',
|
|
155410
|
+
flowsDep: "add @qawolf/flows dependency"
|
|
155411
|
+
},
|
|
155412
|
+
updatePackageJsonPrompt: (changes) => `Update package.json (${changes.join(", ")})?`,
|
|
155398
155413
|
updatedPackageJson: "Updated package.json",
|
|
155399
155414
|
overwritePrompt: (relPath) => `Overwrite ${relPath}?`,
|
|
155400
155415
|
skippedFile: (relPath) => `Skipped ${relPath}`,
|
|
@@ -174611,7 +174626,7 @@ function startUpdateCheck(deps) {
|
|
|
174611
174626
|
// package.json
|
|
174612
174627
|
var package_default = {
|
|
174613
174628
|
name: "@qawolf/cli",
|
|
174614
|
-
version: "1.7.
|
|
174629
|
+
version: "1.7.3",
|
|
174615
174630
|
description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
174616
174631
|
keywords: [
|
|
174617
174632
|
"automation",
|
|
@@ -174671,7 +174686,6 @@ var package_default = {
|
|
|
174671
174686
|
"@clack/prompts": "1.5.1",
|
|
174672
174687
|
"@napi-rs/keyring": "1.3.0",
|
|
174673
174688
|
"@oxc-node/core": "0.1.0",
|
|
174674
|
-
"@playwright/test": "1.62.0",
|
|
174675
174689
|
"@qawolf/api-contracts": "0.22.0",
|
|
174676
174690
|
"@qawolf/emails": "1.1.1",
|
|
174677
174691
|
"@qawolf/flow-targets": "1.0.0",
|
|
@@ -174765,7 +174779,7 @@ function withContext(signals, fn) {
|
|
|
174765
174779
|
try {
|
|
174766
174780
|
const result = await fn(ctx);
|
|
174767
174781
|
if (result !== undefined) {
|
|
174768
|
-
ctx.ui.error(result.error);
|
|
174782
|
+
ctx.ui.error(result.error, result.errorBody);
|
|
174769
174783
|
process.exitCode = result.exitCode ?? 1;
|
|
174770
174784
|
}
|
|
174771
174785
|
} catch (err) {
|
|
@@ -174798,7 +174812,7 @@ function withAuthContext(signals, fn, deps = {}) {
|
|
|
174798
174812
|
apiKeySource: resolved.source
|
|
174799
174813
|
});
|
|
174800
174814
|
if (result !== undefined) {
|
|
174801
|
-
ctx.ui.error(result.error);
|
|
174815
|
+
ctx.ui.error(result.error, result.errorBody);
|
|
174802
174816
|
process.exitCode = result.exitCode ?? 1;
|
|
174803
174817
|
}
|
|
174804
174818
|
} catch (err) {
|
|
@@ -175042,9 +175056,6 @@ function nodeModulesBinCandidates(envDir, name, platform) {
|
|
|
175042
175056
|
function appiumCliCandidates(envDir, platform) {
|
|
175043
175057
|
return nodeModulesBinCandidates(envDir, "appium", platform);
|
|
175044
175058
|
}
|
|
175045
|
-
function playwrightCliCandidates(envDir, platform) {
|
|
175046
|
-
return nodeModulesBinCandidates(envDir, "playwright", platform);
|
|
175047
|
-
}
|
|
175048
175059
|
|
|
175049
175060
|
// src/domains/doctor/checks/androidAppium.ts
|
|
175050
175061
|
function firstLine(result) {
|
|
@@ -175407,19 +175418,48 @@ async function checkNpmRegistry(deps) {
|
|
|
175407
175418
|
return { name: "npm-registry", status: "pass" };
|
|
175408
175419
|
}
|
|
175409
175420
|
|
|
175421
|
+
// src/core/playwrightCli.ts
|
|
175422
|
+
import { join as join13 } from "node:path";
|
|
175423
|
+
function playwrightCliJsPath(envDir) {
|
|
175424
|
+
return join13(envDir, "node_modules", "playwright", "cli.js");
|
|
175425
|
+
}
|
|
175426
|
+
function playwrightCliInvocation(args) {
|
|
175427
|
+
return {
|
|
175428
|
+
cmd: args.execPath,
|
|
175429
|
+
args: [playwrightCliJsPath(args.envDir), ...args.cliArgs],
|
|
175430
|
+
env: { BUN_BE_BUN: "1" }
|
|
175431
|
+
};
|
|
175432
|
+
}
|
|
175433
|
+
|
|
175434
|
+
// src/generated/dependencyVersions.ts
|
|
175435
|
+
var flowsVersion = "0.1.4";
|
|
175436
|
+
var playwrightVersion = "1.62.0";
|
|
175437
|
+
var emailsVersion = "1.1.1";
|
|
175438
|
+
var testkitVersion = "1.1.1";
|
|
175439
|
+
var appiumVersion = "2.11.3";
|
|
175440
|
+
var appiumXcuitestDriverVersion = "9.10.5";
|
|
175441
|
+
var appiumUiautomator2DriverVersion = "3.7.0";
|
|
175442
|
+
var expectWebdriverioVersion = "5.6.5";
|
|
175443
|
+
|
|
175410
175444
|
// src/domains/doctor/checks/playwright.ts
|
|
175411
175445
|
async function checkPlaywright(deps) {
|
|
175412
|
-
const
|
|
175413
|
-
const
|
|
175414
|
-
if (
|
|
175446
|
+
const { envDir } = deps;
|
|
175447
|
+
const cliJsPath = envDir === undefined ? undefined : playwrightCliJsPath(envDir);
|
|
175448
|
+
if (envDir === undefined || cliJsPath === undefined || !deps.checkExists(cliJsPath)) {
|
|
175415
175449
|
return {
|
|
175416
175450
|
name: "playwright",
|
|
175417
175451
|
status: "fail",
|
|
175418
|
-
detail: doctorMessages.playwright.notFound(
|
|
175452
|
+
detail: doctorMessages.playwright.notFound(cliJsPath)
|
|
175419
175453
|
};
|
|
175420
175454
|
}
|
|
175421
|
-
const
|
|
175422
|
-
|
|
175455
|
+
const invocation = playwrightCliInvocation({
|
|
175456
|
+
envDir,
|
|
175457
|
+
execPath: deps.execPath,
|
|
175458
|
+
cliArgs: ["--version"]
|
|
175459
|
+
});
|
|
175460
|
+
const result = await deps.spawn(invocation.cmd, invocation.args, {
|
|
175461
|
+
platform: deps.platform,
|
|
175462
|
+
env: invocation.env
|
|
175423
175463
|
});
|
|
175424
175464
|
if (result.exitCode < 0) {
|
|
175425
175465
|
return {
|
|
@@ -175441,6 +175481,14 @@ async function checkPlaywright(deps) {
|
|
|
175441
175481
|
detail: doctorMessages.playwright.versionUnparseable
|
|
175442
175482
|
};
|
|
175443
175483
|
}
|
|
175484
|
+
if (version2 !== playwrightVersion) {
|
|
175485
|
+
return {
|
|
175486
|
+
name: "playwright",
|
|
175487
|
+
status: "fail",
|
|
175488
|
+
version: version2,
|
|
175489
|
+
detail: doctorMessages.playwright.versionMismatch(version2, playwrightVersion)
|
|
175490
|
+
};
|
|
175491
|
+
}
|
|
175444
175492
|
return { name: "playwright", status: "pass", version: version2 };
|
|
175445
175493
|
}
|
|
175446
175494
|
|
|
@@ -175461,6 +175509,7 @@ async function runChecks(deps) {
|
|
|
175461
175509
|
}),
|
|
175462
175510
|
checkPlaywright({
|
|
175463
175511
|
spawn: deps.spawn,
|
|
175512
|
+
execPath: deps.execPath,
|
|
175464
175513
|
envDir: deps.envDir,
|
|
175465
175514
|
platform: deps.platform,
|
|
175466
175515
|
checkExists: deps.checkExists
|
|
@@ -175520,11 +175569,11 @@ function renderResults(ui, results) {
|
|
|
175520
175569
|
}
|
|
175521
175570
|
|
|
175522
175571
|
// src/domains/flows/ensureDeps.ts
|
|
175523
|
-
import { dirname as dirname4, join as
|
|
175572
|
+
import { dirname as dirname4, join as join14 } from "node:path";
|
|
175524
175573
|
function findEnvDir(flowPath, fs2) {
|
|
175525
175574
|
let dir = dirname4(flowPath);
|
|
175526
175575
|
while (true) {
|
|
175527
|
-
if (fs2.existsSync(
|
|
175576
|
+
if (fs2.existsSync(join14(dir, "package.json")))
|
|
175528
175577
|
return dir;
|
|
175529
175578
|
const parent = dirname4(dir);
|
|
175530
175579
|
if (parent === dir)
|
|
@@ -175550,7 +175599,7 @@ function resolveProjectDirSafe(files, fs2) {
|
|
|
175550
175599
|
}
|
|
175551
175600
|
|
|
175552
175601
|
// src/domains/flows/expand.ts
|
|
175553
|
-
import { join as
|
|
175602
|
+
import { join as join15, resolve as resolve3 } from "node:path";
|
|
175554
175603
|
|
|
175555
175604
|
// node_modules/tinyglobby/dist/index.mjs
|
|
175556
175605
|
import { readdir, readdirSync, realpath, realpathSync, stat, statSync } from "fs";
|
|
@@ -176441,11 +176490,11 @@ function makePeekFlowMeta(fs2) {
|
|
|
176441
176490
|
};
|
|
176442
176491
|
}
|
|
176443
176492
|
async function resolveGlobRoots(cwd, fs2) {
|
|
176444
|
-
const qawolfPath =
|
|
176493
|
+
const qawolfPath = join15(cwd, ".qawolf");
|
|
176445
176494
|
let envDirs = [];
|
|
176446
176495
|
try {
|
|
176447
176496
|
const entries = await fs2.readdirWithTypes(qawolfPath);
|
|
176448
|
-
envDirs = entries.filter((e) => e.isDirectory()).map((e) =>
|
|
176497
|
+
envDirs = entries.filter((e) => e.isDirectory()).map((e) => join15(qawolfPath, e.name));
|
|
176449
176498
|
} catch {}
|
|
176450
176499
|
return [cwd, ...envDirs];
|
|
176451
176500
|
}
|
|
@@ -176470,21 +176519,11 @@ async function expandPatterns(patterns, cwd, logger, fs2) {
|
|
|
176470
176519
|
}
|
|
176471
176520
|
|
|
176472
176521
|
// src/domains/runtimeEnv/clearRuntimeEnv.ts
|
|
176473
|
-
import { join as
|
|
176522
|
+
import { join as join17 } from "node:path";
|
|
176474
176523
|
|
|
176475
176524
|
// src/domains/runtimeEnv/managedEnvDir.ts
|
|
176476
176525
|
import { createHash } from "node:crypto";
|
|
176477
|
-
import { join as
|
|
176478
|
-
|
|
176479
|
-
// src/generated/dependencyVersions.ts
|
|
176480
|
-
var flowsVersion = "0.1.4";
|
|
176481
|
-
var playwrightVersion = "1.62.0";
|
|
176482
|
-
var emailsVersion = "1.1.1";
|
|
176483
|
-
var testkitVersion = "1.1.1";
|
|
176484
|
-
var appiumVersion = "2.11.3";
|
|
176485
|
-
var appiumXcuitestDriverVersion = "9.10.5";
|
|
176486
|
-
var appiumUiautomator2DriverVersion = "3.7.0";
|
|
176487
|
-
var expectWebdriverioVersion = "5.6.5";
|
|
176526
|
+
import { join as join16, resolve as resolve4 } from "node:path";
|
|
176488
176527
|
|
|
176489
176528
|
// src/domains/runtimeEnv/pinnedPackages.ts
|
|
176490
176529
|
var pinnedPackages = [
|
|
@@ -176517,19 +176556,19 @@ function managedEnvBaseDir() {
|
|
|
176517
176556
|
const override = process.env["QAWOLF_RUNTIME_DIR"]?.trim();
|
|
176518
176557
|
if (override)
|
|
176519
176558
|
return resolve4(override);
|
|
176520
|
-
return
|
|
176559
|
+
return join16(getDataDir(), "runtime");
|
|
176521
176560
|
}
|
|
176522
176561
|
function runStagingRoot() {
|
|
176523
176562
|
return `${managedEnvBaseDir()}-runs`;
|
|
176524
176563
|
}
|
|
176525
176564
|
function managedEnvDir() {
|
|
176526
|
-
return
|
|
176565
|
+
return join16(managedEnvBaseDir(), managedEnvHash());
|
|
176527
176566
|
}
|
|
176528
176567
|
async function scaffoldManagedEnv(dir, fs2) {
|
|
176529
176568
|
await fs2.mkdir(dir, { recursive: true });
|
|
176530
176569
|
const dependencies = Object.fromEntries(pinnedPackages.map(({ name, version: version2 }) => [name, version2]));
|
|
176531
|
-
await fs2.writeFile(
|
|
176532
|
-
await fs2.writeFile(
|
|
176570
|
+
await fs2.writeFile(join16(dir, "package.json"), JSON.stringify({ name: "qawolf-runtime", private: true, dependencies }, undefined, 2));
|
|
176571
|
+
await fs2.writeFile(join16(dir, ".npmrc"), `@qawolf:registry=https://registry.npmjs.org/
|
|
176533
176572
|
`);
|
|
176534
176573
|
}
|
|
176535
176574
|
|
|
@@ -176551,14 +176590,14 @@ async function isManagedRuntimeBase(dir, fs2) {
|
|
|
176551
176590
|
for (const entry of entries) {
|
|
176552
176591
|
if (!entry.isDirectory())
|
|
176553
176592
|
return false;
|
|
176554
|
-
if (!await hasRuntimeSentinel(
|
|
176593
|
+
if (!await hasRuntimeSentinel(join17(dir, entry.name), fs2))
|
|
176555
176594
|
return false;
|
|
176556
176595
|
}
|
|
176557
176596
|
return true;
|
|
176558
176597
|
}
|
|
176559
176598
|
async function hasRuntimeSentinel(hashDir, fs2) {
|
|
176560
176599
|
try {
|
|
176561
|
-
const pkg = JSON.parse(await fs2.readFile(
|
|
176600
|
+
const pkg = JSON.parse(await fs2.readFile(join17(hashDir, "package.json")));
|
|
176562
176601
|
return pkg.name === runtimeSentinel;
|
|
176563
176602
|
} catch {
|
|
176564
176603
|
return false;
|
|
@@ -176632,10 +176671,10 @@ function spawnNpmInstall(cwd, spawn2 = spawn) {
|
|
|
176632
176671
|
}
|
|
176633
176672
|
|
|
176634
176673
|
// src/domains/runtimeEnv/resolvePinned.ts
|
|
176635
|
-
import { join as
|
|
176674
|
+
import { join as join18 } from "node:path";
|
|
176636
176675
|
function readInstalledVersion(dir, pkgName, fs2) {
|
|
176637
176676
|
try {
|
|
176638
|
-
const pkgPath =
|
|
176677
|
+
const pkgPath = join18(dir, "node_modules", ...pkgName.split("/"), "package.json");
|
|
176639
176678
|
const raw = JSON.parse(fs2.readFileSync(pkgPath));
|
|
176640
176679
|
const { version: version2 } = raw;
|
|
176641
176680
|
return typeof version2 === "string" ? version2 : undefined;
|
|
@@ -176644,8 +176683,18 @@ function readInstalledVersion(dir, pkgName, fs2) {
|
|
|
176644
176683
|
}
|
|
176645
176684
|
}
|
|
176646
176685
|
var shims = [
|
|
176647
|
-
{
|
|
176648
|
-
|
|
176686
|
+
{
|
|
176687
|
+
name: "playwright",
|
|
176688
|
+
display: "node_modules/playwright/cli.js",
|
|
176689
|
+
candidates: (dir, _platform) => [
|
|
176690
|
+
playwrightCliJsPath(dir)
|
|
176691
|
+
]
|
|
176692
|
+
},
|
|
176693
|
+
{
|
|
176694
|
+
name: "appium",
|
|
176695
|
+
display: "node_modules/.bin/appium",
|
|
176696
|
+
candidates: appiumCliCandidates
|
|
176697
|
+
}
|
|
176649
176698
|
];
|
|
176650
176699
|
function pinnedResolutionFailures(dir, fs2, platform) {
|
|
176651
176700
|
const failures = [];
|
|
@@ -176655,16 +176704,16 @@ function pinnedResolutionFailures(dir, fs2, platform) {
|
|
|
176655
176704
|
failures.push({ kind: "package", name, pinned: version2, installed });
|
|
176656
176705
|
}
|
|
176657
176706
|
}
|
|
176658
|
-
for (const { name, candidates } of shims) {
|
|
176707
|
+
for (const { name, display, candidates } of shims) {
|
|
176659
176708
|
if (!candidates(dir, platform).some((p2) => fs2.existsSync(p2))) {
|
|
176660
|
-
failures.push({ kind: "shim", name });
|
|
176709
|
+
failures.push({ kind: "shim", name, display });
|
|
176661
176710
|
}
|
|
176662
176711
|
}
|
|
176663
176712
|
return failures;
|
|
176664
176713
|
}
|
|
176665
176714
|
function describePinnedFailure(failure) {
|
|
176666
176715
|
if (failure.kind === "shim") {
|
|
176667
|
-
return
|
|
176716
|
+
return `${failure.display} (missing)`;
|
|
176668
176717
|
}
|
|
176669
176718
|
return failure.installed === undefined ? `${failure.name} (missing, pinned ${failure.pinned})` : `${failure.name} ${failure.installed} (pinned ${failure.pinned})`;
|
|
176670
176719
|
}
|
|
@@ -176673,10 +176722,10 @@ function allPinnedResolved(dir, fs2, platform) {
|
|
|
176673
176722
|
}
|
|
176674
176723
|
|
|
176675
176724
|
// src/domains/runtimeEnv/shimDeps.ts
|
|
176676
|
-
import { join as
|
|
176725
|
+
import { join as join20 } from "node:path";
|
|
176677
176726
|
|
|
176678
176727
|
// src/shell/resolveExport.ts
|
|
176679
|
-
import { join as
|
|
176728
|
+
import { join as join19 } from "node:path";
|
|
176680
176729
|
function pickPath(entry, preference) {
|
|
176681
176730
|
if (typeof entry === "string")
|
|
176682
176731
|
return entry;
|
|
@@ -176708,28 +176757,28 @@ function resolveFromEnvDir(envDir, specifier, preference = "esm", fs2 = makeDefa
|
|
|
176708
176757
|
const pkgName = parts.slice(0, pkgPartCount).join("/");
|
|
176709
176758
|
const rest = parts.slice(pkgPartCount);
|
|
176710
176759
|
const subpath = rest.length > 0 ? "./" + rest.join("/") : ".";
|
|
176711
|
-
const pkgDir =
|
|
176760
|
+
const pkgDir = join19(envDir, "node_modules", ...pkgName.split("/"));
|
|
176712
176761
|
let pkg;
|
|
176713
176762
|
try {
|
|
176714
|
-
pkg = JSON.parse(fs2.readFileSync(
|
|
176763
|
+
pkg = JSON.parse(fs2.readFileSync(join19(pkgDir, "package.json")));
|
|
176715
176764
|
} catch (err) {
|
|
176716
176765
|
if (isNoEntError(err))
|
|
176717
|
-
throw new Error(`Package '${pkgName}' not found in ${
|
|
176766
|
+
throw new Error(`Package '${pkgName}' not found in ${join19(envDir, "node_modules")}`, { cause: err });
|
|
176718
176767
|
throw err;
|
|
176719
176768
|
}
|
|
176720
176769
|
const exportsMap = normalizeExports(pkg.exports);
|
|
176721
176770
|
const entry = exportsMap?.[subpath];
|
|
176722
176771
|
const relative3 = pickPath(entry, preference) ?? (subpath === "." ? pkg.module ?? pkg.main : undefined);
|
|
176723
176772
|
if (!relative3) {
|
|
176724
|
-
throw new Error(`No entry for "${subpath}" in exports of ${
|
|
176773
|
+
throw new Error(`No entry for "${subpath}" in exports of ${join19(pkgDir, "package.json")}`);
|
|
176725
176774
|
}
|
|
176726
|
-
return
|
|
176775
|
+
return join19(pkgDir, relative3);
|
|
176727
176776
|
}
|
|
176728
176777
|
|
|
176729
176778
|
// src/domains/runtimeEnv/shimDeps.ts
|
|
176730
176779
|
function readShimMarker(shimDir, fs2) {
|
|
176731
176780
|
try {
|
|
176732
|
-
const pkg = JSON.parse(fs2.readFileSync(
|
|
176781
|
+
const pkg = JSON.parse(fs2.readFileSync(join20(shimDir, "package.json")));
|
|
176733
176782
|
if (pkg._qawolf_format) {
|
|
176734
176783
|
return {
|
|
176735
176784
|
_qawolf_version: pkg._qawolf_version ?? "",
|
|
@@ -176745,11 +176794,11 @@ function resolveBunBuild(bunBuild) {
|
|
|
176745
176794
|
return bunBuild === false ? undefined : { build: bunBuild };
|
|
176746
176795
|
}
|
|
176747
176796
|
async function removeStaleShims(flowsDir, flowsDeps, fs2) {
|
|
176748
|
-
const shimsDir =
|
|
176797
|
+
const shimsDir = join20(flowsDir, "node_modules");
|
|
176749
176798
|
if (!fs2.existsSync(shimsDir))
|
|
176750
176799
|
return;
|
|
176751
176800
|
for (const dep of flowsDeps) {
|
|
176752
|
-
const shimDepDir =
|
|
176801
|
+
const shimDepDir = join20(shimsDir, ...dep.split("/"));
|
|
176753
176802
|
if (readShimMarker(shimDepDir, fs2)) {
|
|
176754
176803
|
await fs2.rm(shimDepDir, { recursive: true, force: true });
|
|
176755
176804
|
}
|
|
@@ -176758,17 +176807,17 @@ async function removeStaleShims(flowsDir, flowsDeps, fs2) {
|
|
|
176758
176807
|
async function buildDepShim(args) {
|
|
176759
176808
|
const { envDir, flowsDir, dep, fs: fs2, build: build2 } = args;
|
|
176760
176809
|
const depParts = dep.split("/");
|
|
176761
|
-
const depDir =
|
|
176810
|
+
const depDir = join20(envDir, "node_modules", ...depParts);
|
|
176762
176811
|
if (!fs2.existsSync(depDir))
|
|
176763
176812
|
return;
|
|
176764
176813
|
let depVersion;
|
|
176765
176814
|
try {
|
|
176766
|
-
const pkg = JSON.parse(fs2.readFileSync(
|
|
176815
|
+
const pkg = JSON.parse(fs2.readFileSync(join20(depDir, "package.json")));
|
|
176767
176816
|
depVersion = pkg.version ?? "unknown";
|
|
176768
176817
|
} catch {
|
|
176769
176818
|
depVersion = "unknown";
|
|
176770
176819
|
}
|
|
176771
|
-
const shimDir =
|
|
176820
|
+
const shimDir = join20(flowsDir, "node_modules", ...depParts);
|
|
176772
176821
|
if (fs2.existsSync(shimDir)) {
|
|
176773
176822
|
const marker = readShimMarker(shimDir, fs2);
|
|
176774
176823
|
if (!marker)
|
|
@@ -176795,20 +176844,20 @@ async function buildDepShim(args) {
|
|
|
176795
176844
|
}
|
|
176796
176845
|
const shimCode = await output.text();
|
|
176797
176846
|
await fs2.mkdir(shimDir, { recursive: true });
|
|
176798
|
-
await fs2.writeFile(
|
|
176847
|
+
await fs2.writeFile(join20(shimDir, "package.json"), JSON.stringify({
|
|
176799
176848
|
name: dep,
|
|
176800
176849
|
_qawolf_version: depVersion,
|
|
176801
176850
|
_qawolf_format: "bun-build-v1"
|
|
176802
176851
|
}));
|
|
176803
|
-
await fs2.writeFile(
|
|
176852
|
+
await fs2.writeFile(join20(shimDir, "index.js"), shimCode);
|
|
176804
176853
|
}
|
|
176805
176854
|
async function shimFlowsDeps(envDir, fs2 = makeDefaultFs(), bunBuild) {
|
|
176806
|
-
const flowsDir =
|
|
176855
|
+
const flowsDir = join20(envDir, "node_modules", "@qawolf", "flows");
|
|
176807
176856
|
if (!fs2.existsSync(flowsDir))
|
|
176808
176857
|
return;
|
|
176809
176858
|
let flowsDeps;
|
|
176810
176859
|
try {
|
|
176811
|
-
const flowsPkg = JSON.parse(fs2.readFileSync(
|
|
176860
|
+
const flowsPkg = JSON.parse(fs2.readFileSync(join20(flowsDir, "package.json")));
|
|
176812
176861
|
flowsDeps = Object.keys(flowsPkg.dependencies ?? {});
|
|
176813
176862
|
} catch {
|
|
176814
176863
|
return;
|
|
@@ -176932,6 +176981,7 @@ async function handleDoctor(ctx, opts) {
|
|
|
176932
176981
|
apiKey: resolved?.key,
|
|
176933
176982
|
fetch: globalThis.fetch,
|
|
176934
176983
|
spawn: defaultSpawn,
|
|
176984
|
+
execPath: process.execPath,
|
|
176935
176985
|
apiBaseUrl: ctx.apiBaseUrl,
|
|
176936
176986
|
enginesNode: package_default.engines.node,
|
|
176937
176987
|
processVersion: process.version,
|
|
@@ -177074,11 +177124,11 @@ async function flowsListRemote(ctx, pattern, options) {
|
|
|
177074
177124
|
}
|
|
177075
177125
|
|
|
177076
177126
|
// src/domains/flows/pull/handler.ts
|
|
177077
|
-
import { dirname as dirname7, join as
|
|
177127
|
+
import { dirname as dirname7, join as join25, resolve as resolve8 } from "node:path";
|
|
177078
177128
|
|
|
177079
177129
|
// src/shell/manifest/io.ts
|
|
177080
177130
|
import { createHash as createHash2 } from "node:crypto";
|
|
177081
|
-
import { join as
|
|
177131
|
+
import { join as join21 } from "node:path";
|
|
177082
177132
|
var manifestFilename = ".manifest.json";
|
|
177083
177133
|
var flowEntrySchema = exports_external.object({
|
|
177084
177134
|
path: exports_external.string(),
|
|
@@ -177097,7 +177147,7 @@ var manifestSchema = exports_external.object({
|
|
|
177097
177147
|
async function readManifest(envDir, fs2 = makeDefaultFs()) {
|
|
177098
177148
|
let raw;
|
|
177099
177149
|
try {
|
|
177100
|
-
raw = await fs2.readFile(
|
|
177150
|
+
raw = await fs2.readFile(join21(envDir, manifestFilename));
|
|
177101
177151
|
} catch (err) {
|
|
177102
177152
|
if (isNoEntError(err))
|
|
177103
177153
|
return "missing";
|
|
@@ -177125,7 +177175,7 @@ async function readManifest(envDir, fs2 = makeDefaultFs()) {
|
|
|
177125
177175
|
}
|
|
177126
177176
|
async function writeManifest(envDir, manifest, fs2 = makeDefaultFs()) {
|
|
177127
177177
|
const body = JSON.stringify(manifest, undefined, 2);
|
|
177128
|
-
await fs2.writeFile(
|
|
177178
|
+
await fs2.writeFile(join21(envDir, manifestFilename), `${body}
|
|
177129
177179
|
`);
|
|
177130
177180
|
}
|
|
177131
177181
|
function hashFile(absPath, fs2 = makeDefaultFs()) {
|
|
@@ -177260,7 +177310,7 @@ async function checkSafety(args) {
|
|
|
177260
177310
|
}
|
|
177261
177311
|
|
|
177262
177312
|
// src/domains/flows/pull/bundle.ts
|
|
177263
|
-
import { join as
|
|
177313
|
+
import { join as join22, relative as relative4 } from "node:path";
|
|
177264
177314
|
async function flattenSingleWrapper(dir, fs2 = makeDefaultFs()) {
|
|
177265
177315
|
const entries = await fs2.readdir(dir);
|
|
177266
177316
|
if (entries.length !== 1)
|
|
@@ -177268,12 +177318,12 @@ async function flattenSingleWrapper(dir, fs2 = makeDefaultFs()) {
|
|
|
177268
177318
|
const innerName = entries[0];
|
|
177269
177319
|
if (!innerName)
|
|
177270
177320
|
return;
|
|
177271
|
-
const inner =
|
|
177321
|
+
const inner = join22(dir, innerName);
|
|
177272
177322
|
const innerStat = await fs2.stat(inner);
|
|
177273
177323
|
if (!innerStat.isDirectory())
|
|
177274
177324
|
return;
|
|
177275
177325
|
for (const e of await fs2.readdir(inner)) {
|
|
177276
|
-
await fs2.rename(
|
|
177326
|
+
await fs2.rename(join22(inner, e), join22(dir, e));
|
|
177277
177327
|
}
|
|
177278
177328
|
const leftovers = await fs2.readdir(inner);
|
|
177279
177329
|
if (leftovers.length > 0) {
|
|
@@ -177292,7 +177342,7 @@ async function buildManifest(args, fs2 = makeDefaultFs()) {
|
|
|
177292
177342
|
const flowPaths = await walkForFlows(args.bundleDir, fs2);
|
|
177293
177343
|
const flows = await Promise.all(flowPaths.map(async (rel) => ({
|
|
177294
177344
|
path: rel,
|
|
177295
|
-
contentHash: await hashFile(
|
|
177345
|
+
contentHash: await hashFile(join22(args.bundleDir, rel), fs2)
|
|
177296
177346
|
})));
|
|
177297
177347
|
return {
|
|
177298
177348
|
envId: args.envId,
|
|
@@ -177313,7 +177363,7 @@ async function walkForFlows(root, fs2) {
|
|
|
177313
177363
|
async function walk(current, root, out, fs2) {
|
|
177314
177364
|
const entries = await fs2.readdirWithTypes(current);
|
|
177315
177365
|
for (const e of entries) {
|
|
177316
|
-
const abs =
|
|
177366
|
+
const abs = join22(current, e.name);
|
|
177317
177367
|
if (e.isDirectory()) {
|
|
177318
177368
|
await walk(abs, root, out, fs2);
|
|
177319
177369
|
} else if (e.isFile() && flowExtensions.some((ext) => e.name.endsWith(ext))) {
|
|
@@ -177326,11 +177376,11 @@ async function sampleQawolfCommittedAt(bundleDir, fs2 = makeDefaultFs()) {
|
|
|
177326
177376
|
const sample = flowPaths[0];
|
|
177327
177377
|
if (!sample)
|
|
177328
177378
|
return;
|
|
177329
|
-
return (await fs2.stat(
|
|
177379
|
+
return (await fs2.stat(join22(bundleDir, sample))).mtime.toISOString();
|
|
177330
177380
|
}
|
|
177331
177381
|
|
|
177332
177382
|
// src/domains/flows/pull/applyTeamStorageRewrite.ts
|
|
177333
|
-
import { join as
|
|
177383
|
+
import { join as join23, relative as relative5 } from "node:path";
|
|
177334
177384
|
|
|
177335
177385
|
// src/domains/flows/pull/rewriteTeamStorage.ts
|
|
177336
177386
|
var runnerMountPrefix = "/home/wolf/team-storage/";
|
|
@@ -177366,7 +177416,7 @@ function isFlowFile(name) {
|
|
|
177366
177416
|
async function walk2(dir, out, fs2) {
|
|
177367
177417
|
const entries = await fs2.readdirWithTypes(dir);
|
|
177368
177418
|
for (const e of entries) {
|
|
177369
|
-
const abs =
|
|
177419
|
+
const abs = join23(dir, e.name);
|
|
177370
177420
|
if (e.isDirectory()) {
|
|
177371
177421
|
await walk2(abs, out, fs2);
|
|
177372
177422
|
} else if (e.isFile() && isSourceFile(e.name)) {
|
|
@@ -177394,7 +177444,7 @@ async function applyTeamStorageRewrite(rootDir, fs2 = makeDefaultFs()) {
|
|
|
177394
177444
|
}
|
|
177395
177445
|
|
|
177396
177446
|
// src/domains/flows/pull/envVars.ts
|
|
177397
|
-
import { join as
|
|
177447
|
+
import { join as join24 } from "node:path";
|
|
177398
177448
|
|
|
177399
177449
|
// src/core/dotenv.ts
|
|
177400
177450
|
var bareKeyPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -177459,7 +177509,7 @@ function unquote(escaped) {
|
|
|
177459
177509
|
async function writeEnvFile(envDir, vars, fs2 = makeDefaultFs()) {
|
|
177460
177510
|
if (Object.keys(vars).length === 0)
|
|
177461
177511
|
return;
|
|
177462
|
-
await fs2.writeFile(
|
|
177512
|
+
await fs2.writeFile(join24(envDir, ".env"), serializeDotenv(vars), {
|
|
177463
177513
|
mode: 384
|
|
177464
177514
|
});
|
|
177465
177515
|
}
|
|
@@ -180832,8 +180882,8 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
180832
180882
|
ctx.ui.error(validation.error);
|
|
180833
180883
|
return { error: validation.error };
|
|
180834
180884
|
}
|
|
180835
|
-
const destAbs = resolve8(opts.out ??
|
|
180836
|
-
const assetsAbs =
|
|
180885
|
+
const destAbs = resolve8(opts.out ?? join25(".qawolf", opts.env));
|
|
180886
|
+
const assetsAbs = join25(dirname7(destAbs), "assets");
|
|
180837
180887
|
await resolvedDeps.fs.mkdir(assetsAbs, { recursive: true });
|
|
180838
180888
|
const yes = opts.yes ?? false;
|
|
180839
180889
|
let archive;
|
|
@@ -180899,7 +180949,7 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
180899
180949
|
assetDownloadedCount: assetResult.downloadedCount,
|
|
180900
180950
|
assetReusedCount: assetResult.reusedCount,
|
|
180901
180951
|
assetSkippedCount: assetResult.skippedCount,
|
|
180902
|
-
manifestPath:
|
|
180952
|
+
manifestPath: join25(result.envDir, manifestFilename)
|
|
180903
180953
|
}, "");
|
|
180904
180954
|
}
|
|
180905
180955
|
} finally {
|
|
@@ -180908,20 +180958,9 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
180908
180958
|
}
|
|
180909
180959
|
}
|
|
180910
180960
|
|
|
180911
|
-
// src/domains/environments/
|
|
180961
|
+
// src/domains/environments/pickEnvironment.ts
|
|
180912
180962
|
var findContract = publicContractsV1.environment.find;
|
|
180913
|
-
async function
|
|
180914
|
-
const explicit = opts.explicit?.trim();
|
|
180915
|
-
if (explicit)
|
|
180916
|
-
return { kind: "resolved", env: explicit };
|
|
180917
|
-
const fromEnvVar = deps.env["QAWOLF_ENVIRONMENT"]?.trim();
|
|
180918
|
-
if (fromEnvVar) {
|
|
180919
|
-
deps.ui.info(environmentsMessages.usingFromEnvVar(fromEnvVar));
|
|
180920
|
-
return { kind: "resolved", env: fromEnvVar };
|
|
180921
|
-
}
|
|
180922
|
-
if (deps.ui.mode !== "human") {
|
|
180923
|
-
return { kind: "error", error: opts.requiredMessage };
|
|
180924
|
-
}
|
|
180963
|
+
async function pickEnvironment(deps) {
|
|
180925
180964
|
const fetched = await fetchAllEnvironments(deps.platformClient);
|
|
180926
180965
|
if (!fetched.ok)
|
|
180927
180966
|
return { kind: "error", error: fetched.error };
|
|
@@ -180994,6 +181033,39 @@ async function fetchAllEnvironments(platformClient) {
|
|
|
180994
181033
|
return { ok: false, error: environmentsMessages.tooManyPages(maxPages) };
|
|
180995
181034
|
}
|
|
180996
181035
|
|
|
181036
|
+
// src/domains/environments/resolveEnvironment.ts
|
|
181037
|
+
var findContract2 = publicContractsV1.environment.find;
|
|
181038
|
+
var getContract = publicContractsV1.environment.get;
|
|
181039
|
+
async function resolveEnvironment(deps, opts) {
|
|
181040
|
+
const explicit = opts.explicit?.trim();
|
|
181041
|
+
if (explicit)
|
|
181042
|
+
return resolveRef2(deps, explicit);
|
|
181043
|
+
const fromEnvVar = deps.env["QAWOLF_ENVIRONMENT"]?.trim();
|
|
181044
|
+
if (fromEnvVar) {
|
|
181045
|
+
deps.ui.info(environmentsMessages.usingFromEnvVar(fromEnvVar));
|
|
181046
|
+
return resolveRef2(deps, fromEnvVar);
|
|
181047
|
+
}
|
|
181048
|
+
if (deps.ui.mode !== "human") {
|
|
181049
|
+
return { kind: "error", error: opts.requiredMessage };
|
|
181050
|
+
}
|
|
181051
|
+
return pickEnvironment(deps);
|
|
181052
|
+
}
|
|
181053
|
+
async function resolveRef2(deps, ref) {
|
|
181054
|
+
const result = await deps.platformClient.callPublicApi(getContract, {
|
|
181055
|
+
environmentId: ref
|
|
181056
|
+
});
|
|
181057
|
+
if (!result.ok) {
|
|
181058
|
+
return {
|
|
181059
|
+
kind: "error",
|
|
181060
|
+
error: environmentsMessages.couldNotResolve(ref, result.error)
|
|
181061
|
+
};
|
|
181062
|
+
}
|
|
181063
|
+
if (result.value.id !== ref) {
|
|
181064
|
+
deps.ui.info(environmentsMessages.resolvedAlias(ref, result.value.id));
|
|
181065
|
+
}
|
|
181066
|
+
return { kind: "resolved", env: result.value.id };
|
|
181067
|
+
}
|
|
181068
|
+
|
|
180997
181069
|
// src/commands/flows/withResolvedEnv.ts
|
|
180998
181070
|
function withResolvedEnv(signals, args, fn2) {
|
|
180999
181071
|
return (opts, command) => {
|
|
@@ -181063,6 +181135,72 @@ function buildPatternArgs(pattern) {
|
|
|
181063
181135
|
return pattern ? [pattern] : [];
|
|
181064
181136
|
}
|
|
181065
181137
|
|
|
181138
|
+
// src/shell/reporter/createCompositeReporter.ts
|
|
181139
|
+
function callEach(reporters, pick2, event) {
|
|
181140
|
+
for (const r2 of reporters) {
|
|
181141
|
+
try {
|
|
181142
|
+
pick2(r2)?.(event);
|
|
181143
|
+
} catch (err) {
|
|
181144
|
+
process.stderr.write(`[reporter error] ${String(err)}
|
|
181145
|
+
`);
|
|
181146
|
+
}
|
|
181147
|
+
}
|
|
181148
|
+
}
|
|
181149
|
+
function createCompositeReporter(reporters) {
|
|
181150
|
+
return {
|
|
181151
|
+
onFlowStart: (e) => callEach(reporters, (r2) => r2.onFlowStart, e),
|
|
181152
|
+
onFlowPass: (e) => callEach(reporters, (r2) => r2.onFlowPass, e),
|
|
181153
|
+
onFlowFail: (e) => callEach(reporters, (r2) => r2.onFlowFail, e),
|
|
181154
|
+
onTestStart: (e) => callEach(reporters, (r2) => r2.onTestStart, e),
|
|
181155
|
+
onTestResult: (e) => callEach(reporters, (r2) => r2.onTestResult, e),
|
|
181156
|
+
onScreenshot: (e) => callEach(reporters, (r2) => r2.onScreenshot, e),
|
|
181157
|
+
onRunComplete: (e) => callEach(reporters, (r2) => r2.onRunComplete, e)
|
|
181158
|
+
};
|
|
181159
|
+
}
|
|
181160
|
+
|
|
181161
|
+
// src/shell/reporter/formatErrorWithCause.ts
|
|
181162
|
+
function filterStack(stack) {
|
|
181163
|
+
const cwd = process.cwd();
|
|
181164
|
+
return stack.split(`
|
|
181165
|
+
`).filter((line) => {
|
|
181166
|
+
if (!/^\s+at /.test(line))
|
|
181167
|
+
return true;
|
|
181168
|
+
return !line.includes("node_modules") && !line.includes("dist/cli.js");
|
|
181169
|
+
}).map((line) => {
|
|
181170
|
+
if (!/^\s+at /.test(line))
|
|
181171
|
+
return line;
|
|
181172
|
+
return line.replace(`file://${cwd}/`, "").replace(`${cwd}/`, "");
|
|
181173
|
+
}).join(`
|
|
181174
|
+
`);
|
|
181175
|
+
}
|
|
181176
|
+
function renderCause(cause) {
|
|
181177
|
+
if (cause instanceof Error)
|
|
181178
|
+
return filterStack(cause.stack ?? cause.message);
|
|
181179
|
+
if (typeof cause === "object" && cause !== null) {
|
|
181180
|
+
const obj = cause;
|
|
181181
|
+
if (typeof obj["message"] === "string")
|
|
181182
|
+
return obj["message"];
|
|
181183
|
+
try {
|
|
181184
|
+
return JSON.stringify(cause);
|
|
181185
|
+
} catch {
|
|
181186
|
+
return String(cause);
|
|
181187
|
+
}
|
|
181188
|
+
}
|
|
181189
|
+
return String(cause);
|
|
181190
|
+
}
|
|
181191
|
+
function formatErrorWithCause(err) {
|
|
181192
|
+
const parts = [String(err)];
|
|
181193
|
+
let cause = err.cause;
|
|
181194
|
+
while (cause !== undefined && cause !== null) {
|
|
181195
|
+
parts.push(`Caused by: ${renderCause(cause)}`);
|
|
181196
|
+
if (!(cause instanceof Error))
|
|
181197
|
+
break;
|
|
181198
|
+
cause = cause.cause;
|
|
181199
|
+
}
|
|
181200
|
+
return parts.join(`
|
|
181201
|
+
`);
|
|
181202
|
+
}
|
|
181203
|
+
|
|
181066
181204
|
// src/domains/runner/runAndroidFlowUtils.ts
|
|
181067
181205
|
import { parseExecutionTarget as parseExecutionTarget3 } from "@qawolf/flow-targets";
|
|
181068
181206
|
|
|
@@ -181410,9 +181548,16 @@ async function flowsRun(ctx, files, flags, deps) {
|
|
|
181410
181548
|
return { error: runnerMessages.androidWorkersUnsupported, exitCode: 2 };
|
|
181411
181549
|
}
|
|
181412
181550
|
const { webOptions, androidOptions } = buildRunOptions(flags);
|
|
181551
|
+
const failureDetails = [];
|
|
181552
|
+
const reporter = ctx.outputMode === "json" ? createCompositeReporter([
|
|
181553
|
+
deps.reporter,
|
|
181554
|
+
{
|
|
181555
|
+
onFlowFail: ({ err }) => failureDetails.push(formatErrorWithCause(err))
|
|
181556
|
+
}
|
|
181557
|
+
]) : deps.reporter;
|
|
181413
181558
|
const result = await executeFlows({
|
|
181414
181559
|
ctx,
|
|
181415
|
-
deps,
|
|
181560
|
+
deps: { ...deps, reporter },
|
|
181416
181561
|
flags,
|
|
181417
181562
|
flows,
|
|
181418
181563
|
webFlows,
|
|
@@ -181440,7 +181585,13 @@ async function flowsRun(ctx, files, flags, deps) {
|
|
|
181440
181585
|
deps.reporter.onRunComplete?.({ summary });
|
|
181441
181586
|
ctx.ui.gap();
|
|
181442
181587
|
if (counts.flowsFailed > 0) {
|
|
181443
|
-
|
|
181588
|
+
const error51 = runnerMessages.flowsFailed(counts.flowsFailed);
|
|
181589
|
+
if (ctx.outputMode === "json" && failureDetails.length > 0) {
|
|
181590
|
+
return { error: error51, errorBody: failureDetails.join(`
|
|
181591
|
+
|
|
181592
|
+
`) };
|
|
181593
|
+
}
|
|
181594
|
+
return { error: error51 };
|
|
181444
181595
|
}
|
|
181445
181596
|
}
|
|
181446
181597
|
|
|
@@ -181491,15 +181642,15 @@ async function defaultRunWebFlowDeps(envDir = process.cwd(), signals) {
|
|
|
181491
181642
|
|
|
181492
181643
|
// src/domains/runtimeEnv/prepareRunDir.ts
|
|
181493
181644
|
import { createHash as createHash4 } from "node:crypto";
|
|
181494
|
-
import { join as
|
|
181645
|
+
import { join as join32, resolve as resolve9 } from "node:path";
|
|
181495
181646
|
|
|
181496
181647
|
// src/domains/runtimeEnv/execSubpathImports.ts
|
|
181497
|
-
import { join as
|
|
181648
|
+
import { join as join26 } from "node:path";
|
|
181498
181649
|
var flowSubpathImports = { "#playwright": "playwright" };
|
|
181499
181650
|
var packageJsonSchema = exports_external.looseObject({ imports: exports_external.record(exports_external.string(), exports_external.unknown()).catch({}) }).catch({ imports: {} });
|
|
181500
181651
|
async function writeExecSubpathImports(args) {
|
|
181501
181652
|
const { execDir, fs: fs3 } = args;
|
|
181502
|
-
const pkgPath =
|
|
181653
|
+
const pkgPath = join26(execDir, "package.json");
|
|
181503
181654
|
const pkg = packageJsonSchema.parse(await readPackageJson(pkgPath, fs3));
|
|
181504
181655
|
const merged = { ...pkg, imports: { ...pkg.imports, ...flowSubpathImports } };
|
|
181505
181656
|
await fs3.writeFile(pkgPath, JSON.stringify(merged, undefined, 2));
|
|
@@ -181521,10 +181672,10 @@ async function readPackageJson(pkgPath, fs3) {
|
|
|
181521
181672
|
}
|
|
181522
181673
|
|
|
181523
181674
|
// src/domains/runtimeEnv/innerHop.ts
|
|
181524
|
-
import { join as
|
|
181675
|
+
import { join as join28 } from "node:path";
|
|
181525
181676
|
|
|
181526
181677
|
// src/domains/runtimeEnv/linkPinnedPackages.ts
|
|
181527
|
-
import { dirname as dirname8, join as
|
|
181678
|
+
import { dirname as dirname8, join as join27 } from "node:path";
|
|
181528
181679
|
|
|
181529
181680
|
// src/domains/runtimeEnv/symlinkDir.ts
|
|
181530
181681
|
import { symlink } from "node:fs/promises";
|
|
@@ -181536,16 +181687,16 @@ async function createDirSymlink(source, target) {
|
|
|
181536
181687
|
// src/domains/runtimeEnv/linkPinnedPackages.ts
|
|
181537
181688
|
async function linkPinnedPackages(args) {
|
|
181538
181689
|
const { depsRoot, nodeModulesDir, fs: fs3 } = args;
|
|
181539
|
-
const managedModules =
|
|
181690
|
+
const managedModules = join27(depsRoot, "node_modules");
|
|
181540
181691
|
await fs3.mkdir(nodeModulesDir, { recursive: true });
|
|
181541
181692
|
for (const { name } of pinnedPackages) {
|
|
181542
181693
|
const segments = name.split("/");
|
|
181543
|
-
const target =
|
|
181694
|
+
const target = join27(nodeModulesDir, ...segments);
|
|
181544
181695
|
if (segments.length > 1) {
|
|
181545
181696
|
await fs3.mkdir(dirname8(target), { recursive: true });
|
|
181546
181697
|
}
|
|
181547
181698
|
await fs3.rm(target, { recursive: true, force: true });
|
|
181548
|
-
await createDirSymlink(
|
|
181699
|
+
await createDirSymlink(join27(managedModules, ...segments), target);
|
|
181549
181700
|
}
|
|
181550
181701
|
}
|
|
181551
181702
|
|
|
@@ -181554,14 +181705,14 @@ async function populateInnerHop(args) {
|
|
|
181554
181705
|
const { depsRoot, execDir, fs: fs3 } = args;
|
|
181555
181706
|
await linkPinnedPackages({
|
|
181556
181707
|
depsRoot,
|
|
181557
|
-
nodeModulesDir:
|
|
181708
|
+
nodeModulesDir: join28(execDir, "node_modules"),
|
|
181558
181709
|
fs: fs3
|
|
181559
181710
|
});
|
|
181560
181711
|
}
|
|
181561
181712
|
|
|
181562
181713
|
// src/domains/runtimeEnv/outerHop.ts
|
|
181563
181714
|
import { lstat } from "node:fs/promises";
|
|
181564
|
-
import { dirname as dirname9, join as
|
|
181715
|
+
import { dirname as dirname9, join as join29 } from "node:path";
|
|
181565
181716
|
var executorPackageNames = new Set(pinnedPackages.map((p3) => p3.name));
|
|
181566
181717
|
async function populateOuterHop(args) {
|
|
181567
181718
|
const { projectDir, runDir, fs: fs3 } = args;
|
|
@@ -181571,7 +181722,7 @@ async function populateOuterHop(args) {
|
|
|
181571
181722
|
const depNames = Object.keys(installableDeps);
|
|
181572
181723
|
const { satisfying, rejected } = await findSatisfyingNodeModulesDir(projectDir, depNames, fs3);
|
|
181573
181724
|
if (satisfying !== undefined) {
|
|
181574
|
-
await createDirSymlink(satisfying,
|
|
181725
|
+
await createDirSymlink(satisfying, join29(runDir, "node_modules"));
|
|
181575
181726
|
return { mode: "symlink", nodeModulesDir: satisfying };
|
|
181576
181727
|
}
|
|
181577
181728
|
if (depNames.length === 0)
|
|
@@ -181580,7 +181731,7 @@ async function populateOuterHop(args) {
|
|
|
181580
181731
|
await installOuterDeps(runDir, installableDeps, fs3, args.install ?? spawnNpmInstall);
|
|
181581
181732
|
await linkPinnedPackages({
|
|
181582
181733
|
depsRoot: args.depsRoot,
|
|
181583
|
-
nodeModulesDir:
|
|
181734
|
+
nodeModulesDir: join29(runDir, "node_modules"),
|
|
181584
181735
|
fs: fs3
|
|
181585
181736
|
});
|
|
181586
181737
|
return { mode: "install", depCount: depNames.length, rejected };
|
|
@@ -181589,10 +181740,10 @@ async function findSatisfyingNodeModulesDir(startDir, depNames, fs3) {
|
|
|
181589
181740
|
const rejected = [];
|
|
181590
181741
|
let dir = startDir;
|
|
181591
181742
|
while (true) {
|
|
181592
|
-
const candidate =
|
|
181743
|
+
const candidate = join29(dir, "node_modules");
|
|
181593
181744
|
const stats = await lstatSafe(candidate);
|
|
181594
181745
|
if (stats !== undefined && stats.isDirectory() && !stats.isSymbolicLink()) {
|
|
181595
|
-
const missing = depNames.filter((name) => !fs3.existsSync(
|
|
181746
|
+
const missing = depNames.filter((name) => !fs3.existsSync(join29(candidate, name, "package.json")));
|
|
181596
181747
|
if (missing.length === 0)
|
|
181597
181748
|
return { satisfying: candidate, rejected };
|
|
181598
181749
|
rejected.push({ dir: candidate, missing });
|
|
@@ -181613,7 +181764,7 @@ async function lstatSafe(path3) {
|
|
|
181613
181764
|
async function readInstallableDeps(projectDir, fs3) {
|
|
181614
181765
|
let content;
|
|
181615
181766
|
try {
|
|
181616
|
-
content = await fs3.readFile(
|
|
181767
|
+
content = await fs3.readFile(join29(projectDir, "package.json"));
|
|
181617
181768
|
} catch {
|
|
181618
181769
|
return {};
|
|
181619
181770
|
}
|
|
@@ -181631,8 +181782,8 @@ async function readInstallableDeps(projectDir, fs3) {
|
|
|
181631
181782
|
return Object.fromEntries(Object.entries(rawDeps).filter(([name]) => !executorPackageNames.has(name)).filter((entry) => typeof entry[1] === "string"));
|
|
181632
181783
|
}
|
|
181633
181784
|
async function installOuterDeps(runDir, deps, fs3, install) {
|
|
181634
|
-
await fs3.writeFile(
|
|
181635
|
-
await fs3.writeFile(
|
|
181785
|
+
await fs3.writeFile(join29(runDir, "package.json"), JSON.stringify({ name: "qawolf-run", private: true, dependencies: deps }, undefined, 2));
|
|
181786
|
+
await fs3.writeFile(join29(runDir, ".npmrc"), `@qawolf:registry=https://registry.npmjs.org/
|
|
181636
181787
|
`);
|
|
181637
181788
|
const result = await install(runDir);
|
|
181638
181789
|
if (result.exitCode !== 0) {
|
|
@@ -181642,14 +181793,14 @@ async function installOuterDeps(runDir, deps, fs3, install) {
|
|
|
181642
181793
|
|
|
181643
181794
|
// src/domains/runtimeEnv/stageFlowFiles.ts
|
|
181644
181795
|
import { createHash as createHash3 } from "node:crypto";
|
|
181645
|
-
import { basename as basename4, dirname as dirname10, join as
|
|
181796
|
+
import { basename as basename4, dirname as dirname10, join as join31, sep as sep4 } from "node:path";
|
|
181646
181797
|
|
|
181647
181798
|
// src/shell/copyDir.ts
|
|
181648
181799
|
import { cp, readdir as readdir2 } from "node:fs/promises";
|
|
181649
|
-
import { basename as basename3, join as
|
|
181800
|
+
import { basename as basename3, join as join30 } from "node:path";
|
|
181650
181801
|
async function copyDirExcluding(source, destination, excludedNames) {
|
|
181651
181802
|
const entries = await readdir2(source, { withFileTypes: true });
|
|
181652
|
-
await Promise.all(entries.filter((entry) => !excludedNames.has(entry.name)).map((entry) => cp(
|
|
181803
|
+
await Promise.all(entries.filter((entry) => !excludedNames.has(entry.name)).map((entry) => cp(join30(source, entry.name), join30(destination, entry.name), {
|
|
181653
181804
|
recursive: true,
|
|
181654
181805
|
filter: (path3) => !excludedNames.has(basename3(path3))
|
|
181655
181806
|
})));
|
|
@@ -181666,14 +181817,14 @@ async function stageFlowFiles(args) {
|
|
|
181666
181817
|
if (files.length > 1) {
|
|
181667
181818
|
return Promise.all(files.map((f3) => stageOneFile(f3, execDir, fs3)));
|
|
181668
181819
|
}
|
|
181669
|
-
await Promise.all(files.map((f3) => fs3.copyFile(f3,
|
|
181670
|
-
return files.map((f3) =>
|
|
181820
|
+
await Promise.all(files.map((f3) => fs3.copyFile(f3, join31(execDir, basename4(f3)))));
|
|
181821
|
+
return files.map((f3) => join31(execDir, basename4(f3)));
|
|
181671
181822
|
}
|
|
181672
181823
|
async function stageOneFile(file2, execDir, fs3) {
|
|
181673
181824
|
const dirHash = createHash3("sha256").update(dirname10(file2)).digest("hex").slice(0, 8);
|
|
181674
|
-
const subDir =
|
|
181825
|
+
const subDir = join31(execDir, dirHash);
|
|
181675
181826
|
await fs3.mkdir(subDir, { recursive: true });
|
|
181676
|
-
const dest =
|
|
181827
|
+
const dest = join31(subDir, basename4(file2));
|
|
181677
181828
|
await fs3.copyFile(file2, dest);
|
|
181678
181829
|
return dest;
|
|
181679
181830
|
}
|
|
@@ -181681,7 +181832,7 @@ function remapPath(file2, projectDir, execDir) {
|
|
|
181681
181832
|
if (file2 === projectDir)
|
|
181682
181833
|
return execDir;
|
|
181683
181834
|
if (file2.startsWith(projectDir + sep4)) {
|
|
181684
|
-
return
|
|
181835
|
+
return join31(execDir, file2.slice(projectDir.length + 1));
|
|
181685
181836
|
}
|
|
181686
181837
|
return;
|
|
181687
181838
|
}
|
|
@@ -181691,10 +181842,10 @@ async function prepareRunDir(args) {
|
|
|
181691
181842
|
const { files, projectDir, depsRoot, runRoot } = args;
|
|
181692
181843
|
const fs3 = args.fs ?? makeDefaultFs();
|
|
181693
181844
|
const runId = buildRunId(projectDir, files);
|
|
181694
|
-
const runDir =
|
|
181845
|
+
const runDir = join32(runRoot, runId);
|
|
181695
181846
|
await fs3.rm(runDir, { recursive: true, force: true });
|
|
181696
181847
|
await fs3.mkdir(runDir, { recursive: true });
|
|
181697
|
-
const execDir =
|
|
181848
|
+
const execDir = join32(runDir, "exec");
|
|
181698
181849
|
await fs3.mkdir(execDir, { recursive: true });
|
|
181699
181850
|
await populateInnerHop({ depsRoot, execDir, fs: fs3 });
|
|
181700
181851
|
const stagedFiles = await stageFlowFiles({ files, projectDir, execDir, fs: fs3 });
|
|
@@ -181725,17 +181876,17 @@ function buildRunId(projectDir, files) {
|
|
|
181725
181876
|
}
|
|
181726
181877
|
|
|
181727
181878
|
// src/shell/testkit.ts
|
|
181728
|
-
import { join as
|
|
181879
|
+
import { join as join33 } from "node:path";
|
|
181729
181880
|
function notAvailableLocally(name) {
|
|
181730
181881
|
throw new Error(runnerMessages.notAvailableLocally(name));
|
|
181731
181882
|
}
|
|
181732
181883
|
async function loadSdkDeps(cwd) {
|
|
181733
|
-
const testkitDir =
|
|
181884
|
+
const testkitDir = join33(cwd, "node_modules", "@qawolf", "testkit");
|
|
181734
181885
|
try {
|
|
181735
181886
|
const clientMod = await importFromPath(resolveFromEnvDir(cwd, "@qawolf/testkit/client"));
|
|
181736
181887
|
if (typeof clientMod.createTestkitClient !== "function")
|
|
181737
181888
|
throw new Error("createTestkitClient is not a function");
|
|
181738
|
-
const scopeMod = await importFromPath(
|
|
181889
|
+
const scopeMod = await importFromPath(join33(testkitDir, "dist", "clientScope.js"));
|
|
181739
181890
|
if (typeof scopeMod.configureTestkitClient !== "function")
|
|
181740
181891
|
throw new Error("configureTestkitClient is not a function");
|
|
181741
181892
|
return {
|
|
@@ -181793,9 +181944,9 @@ async function registerLazyEmailsClient(getInbox, cwd, deps) {
|
|
|
181793
181944
|
}
|
|
181794
181945
|
|
|
181795
181946
|
// src/commands/flows/envVarDeps.ts
|
|
181796
|
-
import { join as
|
|
181947
|
+
import { join as join34 } from "node:path";
|
|
181797
181948
|
function envFilePath(envDir) {
|
|
181798
|
-
return
|
|
181949
|
+
return join34(envDir, ".env");
|
|
181799
181950
|
}
|
|
181800
181951
|
async function readEnv(envDir, fs3) {
|
|
181801
181952
|
try {
|
|
@@ -182292,17 +182443,21 @@ async function findFlowStamp(flowAbsPath) {
|
|
|
182292
182443
|
|
|
182293
182444
|
// src/domains/install/browsers.ts
|
|
182294
182445
|
async function installBrowserList(ctx, browsers, deps) {
|
|
182295
|
-
const
|
|
182296
|
-
|
|
182297
|
-
|
|
182298
|
-
throw new Error(installMessages.playwrightNotFound(candidates[0] ?? deps.envDir));
|
|
182446
|
+
const cliJsPath = playwrightCliJsPath(deps.envDir);
|
|
182447
|
+
if (!deps.checkExists(cliJsPath)) {
|
|
182448
|
+
throw new Error(installMessages.playwrightNotFound(cliJsPath));
|
|
182299
182449
|
}
|
|
182300
182450
|
await ctx.ui.withProgress(browsers.map((browser) => ({
|
|
182301
182451
|
message: installMessages.installingBrowser(browser),
|
|
182302
182452
|
task: async () => {
|
|
182303
|
-
const
|
|
182304
|
-
|
|
182305
|
-
|
|
182453
|
+
const invocation = playwrightCliInvocation({
|
|
182454
|
+
envDir: deps.envDir,
|
|
182455
|
+
execPath: deps.execPath,
|
|
182456
|
+
cliArgs: buildArgs(browser, deps.platform, deps.browserDeps)
|
|
182457
|
+
});
|
|
182458
|
+
const result = await deps.spawn(invocation.cmd, invocation.args, {
|
|
182459
|
+
platform: deps.platform,
|
|
182460
|
+
env: invocation.env
|
|
182306
182461
|
});
|
|
182307
182462
|
if (result.exitCode !== 0) {
|
|
182308
182463
|
throw new Error(formatError2(browser, result));
|
|
@@ -182320,6 +182475,7 @@ async function installBrowsers(ctx, pattern, deps) {
|
|
|
182320
182475
|
}
|
|
182321
182476
|
await installBrowserList(ctx, browsers, {
|
|
182322
182477
|
spawn: deps.spawn,
|
|
182478
|
+
execPath: deps.execPath,
|
|
182323
182479
|
platform: deps.platform,
|
|
182324
182480
|
browserDeps: deps.browserDeps,
|
|
182325
182481
|
envDir: await deps.resolveDepsRoot(files),
|
|
@@ -183194,14 +183350,14 @@ async function runWebFlow({
|
|
|
183194
183350
|
|
|
183195
183351
|
// src/shell/embeddedWorkerCli.ts
|
|
183196
183352
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
183197
|
-
import { basename as basename6, join as
|
|
183353
|
+
import { basename as basename6, join as join35 } from "node:path";
|
|
183198
183354
|
var embeddedCliPathEnv = "QAWOLF_EMBEDDED_CLI_PATH";
|
|
183199
183355
|
function extractEmbeddedWorkerCli() {
|
|
183200
183356
|
const assetPath = process.env[embeddedCliPathEnv];
|
|
183201
183357
|
if (assetPath === undefined || assetPath === "")
|
|
183202
183358
|
return;
|
|
183203
|
-
const dir =
|
|
183204
|
-
const dest =
|
|
183359
|
+
const dir = join35(getDataDir(), "worker");
|
|
183360
|
+
const dest = join35(dir, basename6(assetPath));
|
|
183205
183361
|
if (existsSync3(dest))
|
|
183206
183362
|
return dest;
|
|
183207
183363
|
mkdirSync3(dir, { recursive: true });
|
|
@@ -183360,51 +183516,6 @@ import { dirname as dirname12 } from "node:path";
|
|
|
183360
183516
|
|
|
183361
183517
|
// src/shell/reporter/createConsoleReporter.ts
|
|
183362
183518
|
import { styleText as styleText3 } from "node:util";
|
|
183363
|
-
|
|
183364
|
-
// src/shell/reporter/formatErrorWithCause.ts
|
|
183365
|
-
function filterStack(stack) {
|
|
183366
|
-
const cwd = process.cwd();
|
|
183367
|
-
return stack.split(`
|
|
183368
|
-
`).filter((line) => {
|
|
183369
|
-
if (!/^\s+at /.test(line))
|
|
183370
|
-
return true;
|
|
183371
|
-
return !line.includes("node_modules") && !line.includes("dist/cli.js");
|
|
183372
|
-
}).map((line) => {
|
|
183373
|
-
if (!/^\s+at /.test(line))
|
|
183374
|
-
return line;
|
|
183375
|
-
return line.replace(`file://${cwd}/`, "").replace(`${cwd}/`, "");
|
|
183376
|
-
}).join(`
|
|
183377
|
-
`);
|
|
183378
|
-
}
|
|
183379
|
-
function renderCause(cause) {
|
|
183380
|
-
if (cause instanceof Error)
|
|
183381
|
-
return filterStack(cause.stack ?? cause.message);
|
|
183382
|
-
if (typeof cause === "object" && cause !== null) {
|
|
183383
|
-
const obj = cause;
|
|
183384
|
-
if (typeof obj["message"] === "string")
|
|
183385
|
-
return obj["message"];
|
|
183386
|
-
try {
|
|
183387
|
-
return JSON.stringify(cause);
|
|
183388
|
-
} catch {
|
|
183389
|
-
return String(cause);
|
|
183390
|
-
}
|
|
183391
|
-
}
|
|
183392
|
-
return String(cause);
|
|
183393
|
-
}
|
|
183394
|
-
function formatErrorWithCause(err) {
|
|
183395
|
-
const parts = [String(err)];
|
|
183396
|
-
let cause = err.cause;
|
|
183397
|
-
while (cause !== undefined && cause !== null) {
|
|
183398
|
-
parts.push(`Caused by: ${renderCause(cause)}`);
|
|
183399
|
-
if (!(cause instanceof Error))
|
|
183400
|
-
break;
|
|
183401
|
-
cause = cause.cause;
|
|
183402
|
-
}
|
|
183403
|
-
return parts.join(`
|
|
183404
|
-
`);
|
|
183405
|
-
}
|
|
183406
|
-
|
|
183407
|
-
// src/shell/reporter/createConsoleReporter.ts
|
|
183408
183519
|
function fmtDuration(ms2) {
|
|
183409
183520
|
return `(${(ms2 / 1000).toFixed(2)}s)`;
|
|
183410
183521
|
}
|
|
@@ -183483,30 +183594,8 @@ ${styleText3("dim", "─".repeat(width))}
|
|
|
183483
183594
|
}
|
|
183484
183595
|
};
|
|
183485
183596
|
}
|
|
183486
|
-
// src/shell/reporter/createCompositeReporter.ts
|
|
183487
|
-
function callEach(reporters, pick2, event) {
|
|
183488
|
-
for (const r2 of reporters) {
|
|
183489
|
-
try {
|
|
183490
|
-
pick2(r2)?.(event);
|
|
183491
|
-
} catch (err) {
|
|
183492
|
-
process.stderr.write(`[reporter error] ${String(err)}
|
|
183493
|
-
`);
|
|
183494
|
-
}
|
|
183495
|
-
}
|
|
183496
|
-
}
|
|
183497
|
-
function createCompositeReporter(reporters) {
|
|
183498
|
-
return {
|
|
183499
|
-
onFlowStart: (e) => callEach(reporters, (r2) => r2.onFlowStart, e),
|
|
183500
|
-
onFlowPass: (e) => callEach(reporters, (r2) => r2.onFlowPass, e),
|
|
183501
|
-
onFlowFail: (e) => callEach(reporters, (r2) => r2.onFlowFail, e),
|
|
183502
|
-
onTestStart: (e) => callEach(reporters, (r2) => r2.onTestStart, e),
|
|
183503
|
-
onTestResult: (e) => callEach(reporters, (r2) => r2.onTestResult, e),
|
|
183504
|
-
onScreenshot: (e) => callEach(reporters, (r2) => r2.onScreenshot, e),
|
|
183505
|
-
onRunComplete: (e) => callEach(reporters, (r2) => r2.onRunComplete, e)
|
|
183506
|
-
};
|
|
183507
|
-
}
|
|
183508
183597
|
// src/shell/reporter/createJUnitReporter.ts
|
|
183509
|
-
import { join as
|
|
183598
|
+
import { join as join36 } from "node:path";
|
|
183510
183599
|
|
|
183511
183600
|
// src/shell/reporter/junitXml.ts
|
|
183512
183601
|
function escapeXml(str) {
|
|
@@ -183545,7 +183634,7 @@ ${suites}`;
|
|
|
183545
183634
|
|
|
183546
183635
|
// src/shell/reporter/createJUnitReporter.ts
|
|
183547
183636
|
function resolveJUnitOutputPath(junit, outputDir) {
|
|
183548
|
-
return typeof junit === "string" && junit.trim() !== "" ? junit :
|
|
183637
|
+
return typeof junit === "string" && junit.trim() !== "" ? junit : join36(outputDir, "junit-report.xml");
|
|
183549
183638
|
}
|
|
183550
183639
|
function createJUnitReporter(deps) {
|
|
183551
183640
|
const flows = [];
|
|
@@ -183607,6 +183696,7 @@ function buildFlowsRunDeps(args) {
|
|
|
183607
183696
|
peekFlowMeta: makePeekFlowMeta(ctx.fs),
|
|
183608
183697
|
installBrowsers: (innerCtx, browsers) => installBrowserList(innerCtx, browsers, {
|
|
183609
183698
|
spawn: defaultSpawn,
|
|
183699
|
+
execPath: process.execPath,
|
|
183610
183700
|
platform: process.platform,
|
|
183611
183701
|
browserDeps: flags.browserDeps,
|
|
183612
183702
|
envDir: resolvedDir,
|
|
@@ -183634,11 +183724,11 @@ function buildFlowsRunDeps(args) {
|
|
|
183634
183724
|
|
|
183635
183725
|
// src/commands/flows/loadEnvFile.ts
|
|
183636
183726
|
import { readFile } from "node:fs/promises";
|
|
183637
|
-
import { join as
|
|
183727
|
+
import { join as join37 } from "node:path";
|
|
183638
183728
|
async function loadEnvFile(envDir) {
|
|
183639
183729
|
let content;
|
|
183640
183730
|
try {
|
|
183641
|
-
content = await readFile(
|
|
183731
|
+
content = await readFile(join37(envDir, ".env"), "utf8");
|
|
183642
183732
|
} catch (err) {
|
|
183643
183733
|
if (isNoEntError(err))
|
|
183644
183734
|
return;
|
|
@@ -183739,7 +183829,7 @@ async function handleFlowsRun(ctx, pattern, flags, deps) {
|
|
|
183739
183829
|
}
|
|
183740
183830
|
|
|
183741
183831
|
// src/commands/flows/hybridRunDefaults.ts
|
|
183742
|
-
import { join as
|
|
183832
|
+
import { join as join38, resolve as resolve10 } from "node:path";
|
|
183743
183833
|
function makeDefaultHybridDeps(fs9) {
|
|
183744
183834
|
return {
|
|
183745
183835
|
expandPatterns: (patterns, cwd, logger) => expandPatterns(patterns, cwd, logger, fs9),
|
|
@@ -183758,7 +183848,7 @@ async function handleHybridFlowsRun(ctx, pattern, flags, deps) {
|
|
|
183758
183848
|
if (validation !== "ok") {
|
|
183759
183849
|
return { error: validation.error, exitCode: 2 };
|
|
183760
183850
|
}
|
|
183761
|
-
const envDir = resolve10(
|
|
183851
|
+
const envDir = resolve10(join38(".qawolf", flags.env));
|
|
183762
183852
|
const patternArgs = buildPatternArgs(pattern);
|
|
183763
183853
|
const globFlows = () => resolvedDeps.expandPatterns(patternArgs, envDir, ctx.log("flows"));
|
|
183764
183854
|
let files = await globFlows();
|
|
@@ -183797,8 +183887,10 @@ function registerFlowsRunCommand(flows, signals) {
|
|
|
183797
183887
|
kindNote: "read with --env"
|
|
183798
183888
|
}).description("Run flows matching [pattern], or every flow when omitted; with --env, pull missing flows from that QA Wolf environment").option("--retries <n>", "Retry each failing flow up to this many times", parseInteger("--retries", { min: 0 }), 0).option("--bail", "Stop the run after the first failure", false).option("--workers <n>", "Parallel worker count for web flows", parseInteger("--workers", { min: 1 }), 1).option("--timeout <ms>", "Default timeout for actions and assertions, in milliseconds", parseInteger("--timeout", { min: 0 }), 30000).option("--video <mode>", "Record video: on | off | retain-on-failure", parseEnum("--video", videoModes), videoDefault).option("--trace <mode>", "Record Playwright trace: on | off | retain-on-failure", parseEnum("--trace", traceModes), traceDefault).option("--har <mode>", "Record HAR network log: on | off | retain-on-failure", parseEnum("--har", harModes), harDefault).option("--har-content <mode>", "HAR response bodies: omit | full (full uses more memory)", parseEnum("--har-content", harContentModes), harContentDefault).option("--output-dir <path>", "Directory for run artifacts (videos, traces, HAR)", defaultOutputDir).option("--junit [path]", "Write a JUnit XML report (default: <output-dir>/junit-report.xml)").option("--headed", "Show the browser window instead of headless", false).option("--env <env>", "Pull and run a flow from this environment (UUID or slug) if not cached locally").option("--deps <dir>", "Use this prepared dependency directory instead of auto-installing the runtime; or set QAWOLF_RUNTIME_DIR to relocate the managed runtime").option("--no-browser-deps", "Skip installing OS-level browser dependencies (Linux --with-deps, which needs root); requires the system libraries to already be present").addHelpText("after", runExamples).action((pattern, opts, command) => {
|
|
183799
183889
|
if (opts.env !== undefined) {
|
|
183800
|
-
|
|
183801
|
-
|
|
183890
|
+
return withResolvedEnv(signals, {
|
|
183891
|
+
explicit: opts.env,
|
|
183892
|
+
requiredMessage: flowsMessages.run.requiresEnv
|
|
183893
|
+
}, (ctx, env3) => handleHybridFlowsRun(ctx, pattern, { ...opts, env: env3 }))(opts, command);
|
|
183802
183894
|
}
|
|
183803
183895
|
return withContext(signals, (ctx) => handleFlowsRun(ctx, pattern, opts))(opts, command);
|
|
183804
183896
|
});
|
|
@@ -183902,7 +183994,100 @@ function registerFlowsCommand(program2, signals) {
|
|
|
183902
183994
|
}
|
|
183903
183995
|
|
|
183904
183996
|
// src/domains/init/init.ts
|
|
183905
|
-
import { dirname as dirname13, join as
|
|
183997
|
+
import { dirname as dirname13, join as join40, relative as relative7 } from "node:path";
|
|
183998
|
+
|
|
183999
|
+
// src/domains/init/ensurePackageJson.ts
|
|
184000
|
+
import { join as join39 } from "node:path";
|
|
184001
|
+
async function ensurePackageJson(ctx, yes, deps) {
|
|
184002
|
+
const pkgPath = join39(deps.cwd, "package.json");
|
|
184003
|
+
if (!await deps.fs.pathExists(pkgPath)) {
|
|
184004
|
+
const confirmed2 = await ctx.ui.confirm(initMessages.createPackageJsonPrompt, { yes });
|
|
184005
|
+
if (!confirmed2.ok || !confirmed2.value) {
|
|
184006
|
+
ctx.ui.info(initMessages.skippedCreatingPackageJson);
|
|
184007
|
+
return;
|
|
184008
|
+
}
|
|
184009
|
+
const pkg2 = {
|
|
184010
|
+
private: true,
|
|
184011
|
+
type: "module",
|
|
184012
|
+
dependencies: { "@qawolf/flows": flowsVersion },
|
|
184013
|
+
scripts: { "test:e2e": "qawolf flows run" }
|
|
184014
|
+
};
|
|
184015
|
+
await deps.fs.writeFile(pkgPath, JSON.stringify(pkg2, undefined, 2) + `
|
|
184016
|
+
`);
|
|
184017
|
+
ctx.ui.step(initMessages.createdPackageJson);
|
|
184018
|
+
return;
|
|
184019
|
+
}
|
|
184020
|
+
const raw = await deps.fs.readFile(pkgPath);
|
|
184021
|
+
let parsed;
|
|
184022
|
+
try {
|
|
184023
|
+
parsed = JSON.parse(raw);
|
|
184024
|
+
} catch {
|
|
184025
|
+
ctx.ui.warn(initMessages.packageJsonInvalidJson);
|
|
184026
|
+
return;
|
|
184027
|
+
}
|
|
184028
|
+
if (!isRecord3(parsed)) {
|
|
184029
|
+
ctx.ui.warn(initMessages.packageJsonNotAnObject);
|
|
184030
|
+
return;
|
|
184031
|
+
}
|
|
184032
|
+
const pkg = parsed;
|
|
184033
|
+
const scripts = readSection(ctx, pkg, "scripts");
|
|
184034
|
+
const dependencies = readSection(ctx, pkg, "dependencies");
|
|
184035
|
+
const devDependencies = readSection(ctx, pkg, "devDependencies");
|
|
184036
|
+
const needScript = scripts !== undefined && !scripts["test:e2e"];
|
|
184037
|
+
const priorType = pkg["type"];
|
|
184038
|
+
const needType = priorType !== "module";
|
|
184039
|
+
const needFlowsDep = dependencies !== undefined && !dependencies["@qawolf/flows"] && !devDependencies?.["@qawolf/flows"];
|
|
184040
|
+
const changes = [];
|
|
184041
|
+
if (needScript)
|
|
184042
|
+
changes.push(initMessages.pkgChanges.script);
|
|
184043
|
+
if (needType)
|
|
184044
|
+
changes.push(initMessages.pkgChanges.type);
|
|
184045
|
+
if (needFlowsDep)
|
|
184046
|
+
changes.push(initMessages.pkgChanges.flowsDep);
|
|
184047
|
+
if (changes.length === 0) {
|
|
184048
|
+
ctx.ui.info(initMessages.packageJsonUpToDate);
|
|
184049
|
+
return;
|
|
184050
|
+
}
|
|
184051
|
+
if (scripts !== undefined && scripts["test:e2e"]) {
|
|
184052
|
+
ctx.ui.warn(initMessages.packageJsonHasTestE2e);
|
|
184053
|
+
}
|
|
184054
|
+
const confirmed = await ctx.ui.confirm(initMessages.updatePackageJsonPrompt(changes), { yes, destructive: true });
|
|
184055
|
+
if (!confirmed.ok || !confirmed.value) {
|
|
184056
|
+
ctx.ui.info(initMessages.skippedUpdatingPackageJson);
|
|
184057
|
+
return;
|
|
184058
|
+
}
|
|
184059
|
+
if (needScript && scripts !== undefined) {
|
|
184060
|
+
scripts["test:e2e"] = "qawolf flows run";
|
|
184061
|
+
pkg["scripts"] = scripts;
|
|
184062
|
+
}
|
|
184063
|
+
if (needType)
|
|
184064
|
+
pkg["type"] = "module";
|
|
184065
|
+
if (needFlowsDep && dependencies !== undefined) {
|
|
184066
|
+
dependencies["@qawolf/flows"] = flowsVersion;
|
|
184067
|
+
pkg["dependencies"] = dependencies;
|
|
184068
|
+
}
|
|
184069
|
+
const trailingNewline = raw.endsWith(`
|
|
184070
|
+
`) ? `
|
|
184071
|
+
` : "";
|
|
184072
|
+
await deps.fs.writeFile(pkgPath, JSON.stringify(pkg, undefined, 2) + trailingNewline);
|
|
184073
|
+
ctx.ui.step(initMessages.updatedPackageJson);
|
|
184074
|
+
if (needType && priorType !== undefined) {
|
|
184075
|
+
const label = typeof priorType === "string" ? priorType : JSON.stringify(priorType);
|
|
184076
|
+
ctx.ui.warn(initMessages.typeChanged(label));
|
|
184077
|
+
}
|
|
184078
|
+
}
|
|
184079
|
+
function isRecord3(value) {
|
|
184080
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
184081
|
+
}
|
|
184082
|
+
function readSection(ctx, pkg, key) {
|
|
184083
|
+
const value = pkg[key];
|
|
184084
|
+
if (value === undefined)
|
|
184085
|
+
return {};
|
|
184086
|
+
if (isRecord3(value))
|
|
184087
|
+
return value;
|
|
184088
|
+
ctx.ui.warn(initMessages.packageJsonMalformedSection(key));
|
|
184089
|
+
return;
|
|
184090
|
+
}
|
|
183906
184091
|
|
|
183907
184092
|
// src/domains/init/templates.ts
|
|
183908
184093
|
var qawolfConfigTs = `export default {
|
|
@@ -183940,9 +184125,9 @@ function makeDefaultInitDeps() {
|
|
|
183940
184125
|
async function handleInit(ctx, opts, deps = makeDefaultInitDeps()) {
|
|
183941
184126
|
ctx.ui.gap();
|
|
183942
184127
|
ctx.ui.intro(initMessages.title);
|
|
183943
|
-
const configPath =
|
|
183944
|
-
const flowPath =
|
|
183945
|
-
const gitignorePath =
|
|
184128
|
+
const configPath = join40(deps.cwd, "qawolf.config.ts");
|
|
184129
|
+
const flowPath = join40(deps.cwd, "src", "flows", "example.flow.ts");
|
|
184130
|
+
const gitignorePath = join40(deps.cwd, ".qawolf", ".gitignore");
|
|
183946
184131
|
await writeWithPrompt(ctx, configPath, qawolfConfigTs, opts.yes, deps);
|
|
183947
184132
|
await writeWithPrompt(ctx, flowPath, exampleFlowTs, opts.yes, deps);
|
|
183948
184133
|
await writeWithPrompt(ctx, gitignorePath, qawolfGitignore, opts.yes, deps);
|
|
@@ -183965,54 +184150,6 @@ async function writeWithPrompt(ctx, filePath, content, yes, deps) {
|
|
|
183965
184150
|
await deps.fs.writeFile(filePath, content);
|
|
183966
184151
|
ctx.ui.step(initMessages.createdFile(relPath));
|
|
183967
184152
|
}
|
|
183968
|
-
async function ensurePackageJson(ctx, yes, deps) {
|
|
183969
|
-
const pkgPath = join38(deps.cwd, "package.json");
|
|
183970
|
-
if (!await deps.fs.pathExists(pkgPath)) {
|
|
183971
|
-
const confirmed2 = await ctx.ui.confirm(initMessages.createPackageJsonPrompt, { yes });
|
|
183972
|
-
if (!confirmed2.ok || !confirmed2.value) {
|
|
183973
|
-
ctx.ui.info(initMessages.skippedCreatingPackageJson);
|
|
183974
|
-
return;
|
|
183975
|
-
}
|
|
183976
|
-
const pkg2 = {
|
|
183977
|
-
private: true,
|
|
183978
|
-
type: "module",
|
|
183979
|
-
dependencies: { "@qawolf/flows": flowsVersion },
|
|
183980
|
-
scripts: { "test:e2e": "qawolf flows run" }
|
|
183981
|
-
};
|
|
183982
|
-
await deps.fs.writeFile(pkgPath, JSON.stringify(pkg2, undefined, 2) + `
|
|
183983
|
-
`);
|
|
183984
|
-
ctx.ui.step(initMessages.createdPackageJson);
|
|
183985
|
-
return;
|
|
183986
|
-
}
|
|
183987
|
-
const raw = await deps.fs.readFile(pkgPath);
|
|
183988
|
-
let pkg;
|
|
183989
|
-
try {
|
|
183990
|
-
pkg = JSON.parse(raw);
|
|
183991
|
-
} catch {
|
|
183992
|
-
ctx.ui.warn(initMessages.packageJsonInvalidJson);
|
|
183993
|
-
return;
|
|
183994
|
-
}
|
|
183995
|
-
const scripts = pkg["scripts"] ?? {};
|
|
183996
|
-
if (scripts["test:e2e"]) {
|
|
183997
|
-
ctx.ui.warn(initMessages.packageJsonHasTestE2e);
|
|
183998
|
-
return;
|
|
183999
|
-
}
|
|
184000
|
-
const confirmed = await ctx.ui.confirm(initMessages.addTestE2ePrompt, {
|
|
184001
|
-
yes,
|
|
184002
|
-
destructive: true
|
|
184003
|
-
});
|
|
184004
|
-
if (!confirmed.ok || !confirmed.value) {
|
|
184005
|
-
ctx.ui.info(initMessages.skippedAddingTestE2e);
|
|
184006
|
-
return;
|
|
184007
|
-
}
|
|
184008
|
-
scripts["test:e2e"] = "qawolf flows run";
|
|
184009
|
-
pkg["scripts"] = scripts;
|
|
184010
|
-
const trailingNewline = raw.endsWith(`
|
|
184011
|
-
`) ? `
|
|
184012
|
-
` : "";
|
|
184013
|
-
await deps.fs.writeFile(pkgPath, JSON.stringify(pkg, undefined, 2) + trailingNewline);
|
|
184014
|
-
ctx.ui.step(initMessages.updatedPackageJson);
|
|
184015
|
-
}
|
|
184016
184153
|
|
|
184017
184154
|
// src/commands/init/index.ts
|
|
184018
184155
|
function registerInitCommand(program2, signals) {
|
|
@@ -184028,7 +184165,7 @@ Examples:
|
|
|
184028
184165
|
import { parseExecutionTarget as parseExecutionTarget4 } from "@qawolf/flow-targets";
|
|
184029
184166
|
|
|
184030
184167
|
// src/domains/install/android/avd.ts
|
|
184031
|
-
import { join as
|
|
184168
|
+
import { join as join41 } from "node:path";
|
|
184032
184169
|
async function installAvds(ctx, specs, deps) {
|
|
184033
184170
|
const sdkManagerPath = sdkManagerBin(deps.androidHome, deps.platform);
|
|
184034
184171
|
const avdManagerPath = avdManagerBin(deps.androidHome, deps.platform);
|
|
@@ -184038,7 +184175,7 @@ async function installAvds(ctx, specs, deps) {
|
|
|
184038
184175
|
if (versionResult.exitCode !== 0) {
|
|
184039
184176
|
throw new Error(installMessages.android.sdkmanagerNotFound(sdkManagerPath));
|
|
184040
184177
|
}
|
|
184041
|
-
const licenseFile =
|
|
184178
|
+
const licenseFile = join41(deps.androidHome, "licenses", "android-sdk-license");
|
|
184042
184179
|
if (deps.checkExists(licenseFile)) {
|
|
184043
184180
|
ctx.ui.info(installMessages.android.licensesAlreadyAccepted);
|
|
184044
184181
|
} else {
|
|
@@ -184053,7 +184190,7 @@ async function installAvds(ctx, specs, deps) {
|
|
|
184053
184190
|
for (const spec of specs) {
|
|
184054
184191
|
if (installedImages.has(spec.systemImage))
|
|
184055
184192
|
continue;
|
|
184056
|
-
const systemImg =
|
|
184193
|
+
const systemImg = join41(deps.androidHome, ...spec.systemImage.split(";"), "system.img");
|
|
184057
184194
|
if (deps.checkExists(systemImg)) {
|
|
184058
184195
|
ctx.ui.info(installMessages.android.systemImageAlreadyInstalled(spec.systemImage));
|
|
184059
184196
|
installedImages.add(spec.systemImage);
|
|
@@ -184207,6 +184344,7 @@ async function handleInstallBrowsers(ctx, pattern, options) {
|
|
|
184207
184344
|
return installBrowsers(ctx, pattern, {
|
|
184208
184345
|
cwd,
|
|
184209
184346
|
spawn: defaultSpawn,
|
|
184347
|
+
execPath: process.execPath,
|
|
184210
184348
|
platform: process.platform,
|
|
184211
184349
|
browserDeps,
|
|
184212
184350
|
expandPatterns: (patterns, dir) => expandPatterns(patterns, dir ?? cwd, undefined, fs9),
|
|
@@ -184697,4 +184835,4 @@ createProgram({ signals }).parseAsync().catch(() => {
|
|
|
184697
184835
|
process.exitCode = 1;
|
|
184698
184836
|
}).finally(() => flushAndExit(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
184699
184837
|
|
|
184700
|
-
//# debugId=
|
|
184838
|
+
//# debugId=C0B1B96CCF6C4A9564756E2164756E21
|