@validate.qa/runner 1.0.20 → 1.0.22
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 +28 -2
- package/dist/cli.mjs +28 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -66068,6 +66068,8 @@ ${constraints.join("\n")}`);
|
|
|
66068
66068
|
function buildMobileFallbackScenarios(input) {
|
|
66069
66069
|
if (input.mode === "survey")
|
|
66070
66070
|
return [];
|
|
66071
|
+
if (input.featureName?.trim())
|
|
66072
|
+
return [];
|
|
66071
66073
|
const orderedScreens = targetAppScreens(input.graph, input.appId).filter((state2) => state2.screenType?.toLowerCase() !== "error").filter((state2) => state2.visited || state2.firstSeenIteration === 0).sort((a, b) => a.firstSeenIteration - b.firstSeenIteration);
|
|
66072
66074
|
if (orderedScreens.length === 0)
|
|
66073
66075
|
return [];
|
|
@@ -66215,6 +66217,15 @@ ${constraints.join("\n")}`);
|
|
|
66215
66217
|
fallbackReason: result.fallbackReason ?? "Mobile planner produced no scenarios"
|
|
66216
66218
|
};
|
|
66217
66219
|
}
|
|
66220
|
+
if (input.featureName?.trim()) {
|
|
66221
|
+
return {
|
|
66222
|
+
...result,
|
|
66223
|
+
featureGroups: mobileFeatureGroups,
|
|
66224
|
+
warning: [result.warning, `Deep discovery could not plan any scenarios for "${input.featureName}" \u2014 the explorer did not reach that feature's screens this run. If the feature requires a signed-in session, verify TEST_USER_EMAIL / TEST_USER_PASSWORD are valid for this app, then re-run.`].filter(Boolean).join(" | "),
|
|
66225
|
+
fallbackUsed: true,
|
|
66226
|
+
fallbackReason: result.fallbackReason ?? `Planner produced no scenarios for feature "${input.featureName}"`
|
|
66227
|
+
};
|
|
66228
|
+
}
|
|
66218
66229
|
}
|
|
66219
66230
|
if (input.mode === "survey" && result.featureGroups.length === 0 && mobileFeatureGroups.length > 0) {
|
|
66220
66231
|
return {
|
|
@@ -66495,7 +66506,8 @@ Max iterations: ${MAX_SCENARIO_ITERATIONS}. You will be warned near the end.`;
|
|
|
66495
66506
|
This app has stored login credentials under these keys:
|
|
66496
66507
|
${keyList}
|
|
66497
66508
|
|
|
66498
|
-
When a scenario needs a signed-in session
|
|
66509
|
+
When a scenario needs a signed-in session, complete the FULL login sequence \u2014 filling the fields alone does NOT log you in:
|
|
66510
|
+
1. Reach the email/password form. 2. Fill each credential field with \`mobile_fill_credential\` (pass the field ref and the KEY, e.g. \`{ ref: "e5", credentialKey: "TEST_USER_EMAIL" }\`) \u2014 the runner types the real value on the device and the generated test stores a \`{{KEY}}\` placeholder that replay resolves; you never see the secret. 3. TAP THE SUBMIT button (Sign In / Log In / Continue). 4. Re-snapshot and VERIFY an authenticated screen appeared. If login fails twice, do NOT keep retrying or wander: call finish_generate with verified:false and say the login could not be completed (the credentials may be invalid for this app).
|
|
66499
66511
|
|
|
66500
66512
|
SECURITY RULES:
|
|
66501
66513
|
- NEVER call \`mobile_type\` with a real email, password, or token value \u2014 the runner will REJECT the call and you lose an iteration. Use \`mobile_fill_credential\` for every credential field.
|
|
@@ -328471,7 +328483,7 @@ var require_package4 = __commonJS({
|
|
|
328471
328483
|
"package.json"(exports2, module2) {
|
|
328472
328484
|
module2.exports = {
|
|
328473
328485
|
name: "@validate.qa/runner",
|
|
328474
|
-
version: "1.0.
|
|
328486
|
+
version: "1.0.22",
|
|
328475
328487
|
description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
|
|
328476
328488
|
bin: {
|
|
328477
328489
|
"validate-runner": "dist/cli.js"
|
|
@@ -330240,6 +330252,10 @@ async function startMobileNetworkCapture(options) {
|
|
|
330240
330252
|
|
|
330241
330253
|
// src/services/appium-executor.ts
|
|
330242
330254
|
var DEFAULT_STEP_TIMEOUT_MS = 1e4;
|
|
330255
|
+
var MOBILE_NEW_COMMAND_TIMEOUT_SECONDS = (() => {
|
|
330256
|
+
const raw = Number(process.env.VALIDATEQA_MOBILE_NEW_COMMAND_TIMEOUT);
|
|
330257
|
+
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 600;
|
|
330258
|
+
})();
|
|
330243
330259
|
var VERIFICATION_ACTIONS = /* @__PURE__ */ new Set(["assertVisible", "assertText", "waitForElement"]);
|
|
330244
330260
|
var WD_SESSION_CREATE_TIMEOUT_MS = 12e4;
|
|
330245
330261
|
var WD_ACTION_TIMEOUT_MS = 3e4;
|
|
@@ -330339,6 +330355,14 @@ async function createSession(target) {
|
|
|
330339
330355
|
...target.deviceId ? { "appium:udid": target.deviceId } : {},
|
|
330340
330356
|
...target.platformVersion ? { "appium:platformVersion": target.platformVersion } : {},
|
|
330341
330357
|
"appium:noReset": true,
|
|
330358
|
+
// Appium's default newCommandTimeout is 60s — it kills the session if no
|
|
330359
|
+
// WebDriver command arrives in that window. A discovery session is driven
|
|
330360
|
+
// by an AI loop where a single model turn (or a pause on a permission
|
|
330361
|
+
// dialog) can exceed 60s, so the default silently terminates the session
|
|
330362
|
+
// mid-run and every later command 404s ("invalid session id"), failing the
|
|
330363
|
+
// whole survey. The runner owns session teardown explicitly, so a long
|
|
330364
|
+
// idle window is safe. Env-overridable.
|
|
330365
|
+
"appium:newCommandTimeout": MOBILE_NEW_COMMAND_TIMEOUT_SECONDS,
|
|
330342
330366
|
...realCaps
|
|
330343
330367
|
} : {
|
|
330344
330368
|
platformName: "Android",
|
|
@@ -330347,6 +330371,8 @@ async function createSession(target) {
|
|
|
330347
330371
|
...target.deviceId ? { "appium:udid": target.deviceId } : {},
|
|
330348
330372
|
...target.platformVersion ? { "appium:platformVersion": target.platformVersion } : {},
|
|
330349
330373
|
"appium:noReset": true,
|
|
330374
|
+
// See the iOS branch: the 60s default kills AI-driven discovery sessions.
|
|
330375
|
+
"appium:newCommandTimeout": MOBILE_NEW_COMMAND_TIMEOUT_SECONDS,
|
|
330350
330376
|
...realCaps
|
|
330351
330377
|
};
|
|
330352
330378
|
const result = await wdRequest("/session", {
|
package/dist/cli.mjs
CHANGED
|
@@ -66073,6 +66073,8 @@ ${constraints.join("\n")}`);
|
|
|
66073
66073
|
function buildMobileFallbackScenarios(input) {
|
|
66074
66074
|
if (input.mode === "survey")
|
|
66075
66075
|
return [];
|
|
66076
|
+
if (input.featureName?.trim())
|
|
66077
|
+
return [];
|
|
66076
66078
|
const orderedScreens = targetAppScreens(input.graph, input.appId).filter((state2) => state2.screenType?.toLowerCase() !== "error").filter((state2) => state2.visited || state2.firstSeenIteration === 0).sort((a, b) => a.firstSeenIteration - b.firstSeenIteration);
|
|
66077
66079
|
if (orderedScreens.length === 0)
|
|
66078
66080
|
return [];
|
|
@@ -66220,6 +66222,15 @@ ${constraints.join("\n")}`);
|
|
|
66220
66222
|
fallbackReason: result.fallbackReason ?? "Mobile planner produced no scenarios"
|
|
66221
66223
|
};
|
|
66222
66224
|
}
|
|
66225
|
+
if (input.featureName?.trim()) {
|
|
66226
|
+
return {
|
|
66227
|
+
...result,
|
|
66228
|
+
featureGroups: mobileFeatureGroups,
|
|
66229
|
+
warning: [result.warning, `Deep discovery could not plan any scenarios for "${input.featureName}" \u2014 the explorer did not reach that feature's screens this run. If the feature requires a signed-in session, verify TEST_USER_EMAIL / TEST_USER_PASSWORD are valid for this app, then re-run.`].filter(Boolean).join(" | "),
|
|
66230
|
+
fallbackUsed: true,
|
|
66231
|
+
fallbackReason: result.fallbackReason ?? `Planner produced no scenarios for feature "${input.featureName}"`
|
|
66232
|
+
};
|
|
66233
|
+
}
|
|
66223
66234
|
}
|
|
66224
66235
|
if (input.mode === "survey" && result.featureGroups.length === 0 && mobileFeatureGroups.length > 0) {
|
|
66225
66236
|
return {
|
|
@@ -66500,7 +66511,8 @@ Max iterations: ${MAX_SCENARIO_ITERATIONS}. You will be warned near the end.`;
|
|
|
66500
66511
|
This app has stored login credentials under these keys:
|
|
66501
66512
|
${keyList}
|
|
66502
66513
|
|
|
66503
|
-
When a scenario needs a signed-in session
|
|
66514
|
+
When a scenario needs a signed-in session, complete the FULL login sequence \u2014 filling the fields alone does NOT log you in:
|
|
66515
|
+
1. Reach the email/password form. 2. Fill each credential field with \`mobile_fill_credential\` (pass the field ref and the KEY, e.g. \`{ ref: "e5", credentialKey: "TEST_USER_EMAIL" }\`) \u2014 the runner types the real value on the device and the generated test stores a \`{{KEY}}\` placeholder that replay resolves; you never see the secret. 3. TAP THE SUBMIT button (Sign In / Log In / Continue). 4. Re-snapshot and VERIFY an authenticated screen appeared. If login fails twice, do NOT keep retrying or wander: call finish_generate with verified:false and say the login could not be completed (the credentials may be invalid for this app).
|
|
66504
66516
|
|
|
66505
66517
|
SECURITY RULES:
|
|
66506
66518
|
- NEVER call \`mobile_type\` with a real email, password, or token value \u2014 the runner will REJECT the call and you lose an iteration. Use \`mobile_fill_credential\` for every credential field.
|
|
@@ -328476,7 +328488,7 @@ var require_package4 = __commonJS({
|
|
|
328476
328488
|
"package.json"(exports, module) {
|
|
328477
328489
|
module.exports = {
|
|
328478
328490
|
name: "@validate.qa/runner",
|
|
328479
|
-
version: "1.0.
|
|
328491
|
+
version: "1.0.22",
|
|
328480
328492
|
description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
|
|
328481
328493
|
bin: {
|
|
328482
328494
|
"validate-runner": "dist/cli.js"
|
|
@@ -330248,6 +330260,10 @@ async function startMobileNetworkCapture(options) {
|
|
|
330248
330260
|
|
|
330249
330261
|
// src/services/appium-executor.ts
|
|
330250
330262
|
var DEFAULT_STEP_TIMEOUT_MS = 1e4;
|
|
330263
|
+
var MOBILE_NEW_COMMAND_TIMEOUT_SECONDS = (() => {
|
|
330264
|
+
const raw = Number(process.env.VALIDATEQA_MOBILE_NEW_COMMAND_TIMEOUT);
|
|
330265
|
+
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 600;
|
|
330266
|
+
})();
|
|
330251
330267
|
var VERIFICATION_ACTIONS = /* @__PURE__ */ new Set(["assertVisible", "assertText", "waitForElement"]);
|
|
330252
330268
|
var WD_SESSION_CREATE_TIMEOUT_MS = 12e4;
|
|
330253
330269
|
var WD_ACTION_TIMEOUT_MS = 3e4;
|
|
@@ -330347,6 +330363,14 @@ async function createSession(target) {
|
|
|
330347
330363
|
...target.deviceId ? { "appium:udid": target.deviceId } : {},
|
|
330348
330364
|
...target.platformVersion ? { "appium:platformVersion": target.platformVersion } : {},
|
|
330349
330365
|
"appium:noReset": true,
|
|
330366
|
+
// Appium's default newCommandTimeout is 60s — it kills the session if no
|
|
330367
|
+
// WebDriver command arrives in that window. A discovery session is driven
|
|
330368
|
+
// by an AI loop where a single model turn (or a pause on a permission
|
|
330369
|
+
// dialog) can exceed 60s, so the default silently terminates the session
|
|
330370
|
+
// mid-run and every later command 404s ("invalid session id"), failing the
|
|
330371
|
+
// whole survey. The runner owns session teardown explicitly, so a long
|
|
330372
|
+
// idle window is safe. Env-overridable.
|
|
330373
|
+
"appium:newCommandTimeout": MOBILE_NEW_COMMAND_TIMEOUT_SECONDS,
|
|
330350
330374
|
...realCaps
|
|
330351
330375
|
} : {
|
|
330352
330376
|
platformName: "Android",
|
|
@@ -330355,6 +330379,8 @@ async function createSession(target) {
|
|
|
330355
330379
|
...target.deviceId ? { "appium:udid": target.deviceId } : {},
|
|
330356
330380
|
...target.platformVersion ? { "appium:platformVersion": target.platformVersion } : {},
|
|
330357
330381
|
"appium:noReset": true,
|
|
330382
|
+
// See the iOS branch: the 60s default kills AI-driven discovery sessions.
|
|
330383
|
+
"appium:newCommandTimeout": MOBILE_NEW_COMMAND_TIMEOUT_SECONDS,
|
|
330358
330384
|
...realCaps
|
|
330359
330385
|
};
|
|
330360
330386
|
const result = await wdRequest("/session", {
|
package/package.json
CHANGED