@hasna/testers 0.0.37 → 0.0.38
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/index.js +86 -6
- package/dist/index.js +78 -3
- package/dist/lib/quick-qa.d.ts +11 -2
- package/dist/lib/quick-qa.d.ts.map +1 -1
- package/dist/lib/runner.d.ts +2 -0
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/mcp/index.js +11 -2
- package/dist/server/index.js +10 -2
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -18137,6 +18137,7 @@ __export(exports_runner, {
|
|
|
18137
18137
|
runByFilter: () => runByFilter,
|
|
18138
18138
|
runBatch: () => runBatch,
|
|
18139
18139
|
resolveScenariosForRun: () => resolveScenariosForRun,
|
|
18140
|
+
resolveAgentMaxTurns: () => resolveAgentMaxTurns,
|
|
18140
18141
|
resolveAgentApiKeyForModel: () => resolveAgentApiKeyForModel,
|
|
18141
18142
|
onRunEvent: () => onRunEvent,
|
|
18142
18143
|
applyStructuredAssertionsToResult: () => applyStructuredAssertionsToResult
|
|
@@ -18154,6 +18155,14 @@ function emit(event) {
|
|
|
18154
18155
|
function resolveAgentApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
18155
18156
|
return resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey);
|
|
18156
18157
|
}
|
|
18158
|
+
function resolveAgentMaxTurns(options) {
|
|
18159
|
+
if (options.maxTurns !== undefined) {
|
|
18160
|
+
const parsed = Math.floor(options.maxTurns);
|
|
18161
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
18162
|
+
return parsed;
|
|
18163
|
+
}
|
|
18164
|
+
return options.minimal ? 10 : 30;
|
|
18165
|
+
}
|
|
18157
18166
|
function assertionDescription(result) {
|
|
18158
18167
|
return result.assertion.description || `${result.assertion.type}${result.assertion.selector ? ` ${result.assertion.selector}` : ""}`;
|
|
18159
18168
|
}
|
|
@@ -18373,7 +18382,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
18373
18382
|
runId,
|
|
18374
18383
|
sessionId: result.id,
|
|
18375
18384
|
baseUrl: options.url,
|
|
18376
|
-
maxTurns: effectiveOptions
|
|
18385
|
+
maxTurns: resolveAgentMaxTurns(effectiveOptions),
|
|
18377
18386
|
a11y: effectiveOptions.a11y,
|
|
18378
18387
|
persona: persona ? {
|
|
18379
18388
|
name: persona.name,
|
|
@@ -93980,7 +93989,7 @@ import chalk6 from "chalk";
|
|
|
93980
93989
|
// package.json
|
|
93981
93990
|
var package_default = {
|
|
93982
93991
|
name: "@hasna/testers",
|
|
93983
|
-
version: "0.0.
|
|
93992
|
+
version: "0.0.38",
|
|
93984
93993
|
description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
|
|
93985
93994
|
type: "module",
|
|
93986
93995
|
main: "dist/index.js",
|
|
@@ -94558,6 +94567,7 @@ function formatSmokeReport(result) {
|
|
|
94558
94567
|
|
|
94559
94568
|
// src/lib/quick-qa.ts
|
|
94560
94569
|
init_health_scan();
|
|
94570
|
+
var DEFAULT_QUICK_QA_OVERALL_TIMEOUT_MS = 120000;
|
|
94561
94571
|
var DEFAULT_QUICK_QA_SCANNERS = [
|
|
94562
94572
|
"console",
|
|
94563
94573
|
"network",
|
|
@@ -94608,7 +94618,17 @@ function resolveQuickQaSelection(options = {}) {
|
|
|
94608
94618
|
}
|
|
94609
94619
|
async function runQuickQa(options) {
|
|
94610
94620
|
const start = Date.now();
|
|
94611
|
-
const
|
|
94621
|
+
const timeoutMs = options.overallTimeoutMs ?? DEFAULT_QUICK_QA_OVERALL_TIMEOUT_MS;
|
|
94622
|
+
return withQuickQaTimeout(runQuickQaUnbounded(options, start), {
|
|
94623
|
+
url: options.url,
|
|
94624
|
+
start,
|
|
94625
|
+
timeoutMs
|
|
94626
|
+
});
|
|
94627
|
+
}
|
|
94628
|
+
async function runQuickQaUnbounded(options, start) {
|
|
94629
|
+
const healthScanner = options.healthScanner ?? runHealthScan;
|
|
94630
|
+
const smokeRunner = options.smokeRunner ?? runSmoke;
|
|
94631
|
+
const health = await healthScanner({
|
|
94612
94632
|
url: options.url,
|
|
94613
94633
|
pages: options.pages,
|
|
94614
94634
|
projectId: options.projectId,
|
|
@@ -94618,7 +94638,7 @@ async function runQuickQa(options) {
|
|
|
94618
94638
|
maxPages: options.maxPages,
|
|
94619
94639
|
wcagLevel: options.wcagLevel
|
|
94620
94640
|
});
|
|
94621
|
-
const smoke = options.includeSmoke === false ? null : await
|
|
94641
|
+
const smoke = options.includeSmoke === false ? null : await smokeRunner({
|
|
94622
94642
|
url: options.url,
|
|
94623
94643
|
model: options.model,
|
|
94624
94644
|
headed: options.headed,
|
|
@@ -94632,6 +94652,62 @@ async function runQuickQa(options) {
|
|
|
94632
94652
|
durationMs: Date.now() - start
|
|
94633
94653
|
});
|
|
94634
94654
|
}
|
|
94655
|
+
function withQuickQaTimeout(promise, options) {
|
|
94656
|
+
if (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)
|
|
94657
|
+
return promise;
|
|
94658
|
+
return new Promise((resolve, reject) => {
|
|
94659
|
+
const timer = setTimeout(() => {
|
|
94660
|
+
resolve(buildQuickQaTimeoutResult({
|
|
94661
|
+
url: options.url,
|
|
94662
|
+
start: options.start,
|
|
94663
|
+
timeoutMs: options.timeoutMs
|
|
94664
|
+
}));
|
|
94665
|
+
}, options.timeoutMs);
|
|
94666
|
+
promise.then((result) => {
|
|
94667
|
+
clearTimeout(timer);
|
|
94668
|
+
resolve(result);
|
|
94669
|
+
}, (error) => {
|
|
94670
|
+
clearTimeout(timer);
|
|
94671
|
+
reject(error);
|
|
94672
|
+
});
|
|
94673
|
+
});
|
|
94674
|
+
}
|
|
94675
|
+
function buildQuickQaTimeoutResult(input) {
|
|
94676
|
+
const now2 = new Date;
|
|
94677
|
+
const durationMs = Math.max(0, Date.now() - input.start);
|
|
94678
|
+
const message = `Quick QA timed out after ${input.timeoutMs}ms before all checks finished. Increase --overall-timeout or skip slow checks.`;
|
|
94679
|
+
const health = {
|
|
94680
|
+
url: input.url,
|
|
94681
|
+
scannedAt: now2.toISOString(),
|
|
94682
|
+
durationMs,
|
|
94683
|
+
totalIssues: 1,
|
|
94684
|
+
newIssues: 1,
|
|
94685
|
+
regressedIssues: 0,
|
|
94686
|
+
existingIssues: 0,
|
|
94687
|
+
results: [{
|
|
94688
|
+
url: input.url,
|
|
94689
|
+
pages: [input.url],
|
|
94690
|
+
scannedAt: now2.toISOString(),
|
|
94691
|
+
durationMs,
|
|
94692
|
+
issues: [{
|
|
94693
|
+
type: "performance",
|
|
94694
|
+
severity: "high",
|
|
94695
|
+
pageUrl: input.url,
|
|
94696
|
+
message,
|
|
94697
|
+
detail: {
|
|
94698
|
+
check: "quick-qa",
|
|
94699
|
+
timeoutMs: input.timeoutMs
|
|
94700
|
+
}
|
|
94701
|
+
}]
|
|
94702
|
+
}]
|
|
94703
|
+
};
|
|
94704
|
+
return buildQuickQaResult({
|
|
94705
|
+
url: input.url,
|
|
94706
|
+
health,
|
|
94707
|
+
smoke: null,
|
|
94708
|
+
durationMs
|
|
94709
|
+
});
|
|
94710
|
+
}
|
|
94635
94711
|
function buildQuickQaResult(input) {
|
|
94636
94712
|
const healthActionable = input.health.newIssues + input.health.regressedIssues;
|
|
94637
94713
|
const smokeIssues = input.smoke?.issuesFound.length ?? 0;
|
|
@@ -97476,7 +97552,7 @@ program2.command("remove <id>").alias("uninstall").description("Remove a scenari
|
|
|
97476
97552
|
program2.command("run [url] [description]").alias("test").description("Run test scenarios against a URL").option("-t, --tag <tag>", "Filter by tag (repeatable)", (val, acc) => {
|
|
97477
97553
|
acc.push(val);
|
|
97478
97554
|
return acc;
|
|
97479
|
-
}, []).option("-s, --scenario <id>", "Run specific scenario ID").option("-p, --priority <level>", "Filter by priority").option("--headed", "Run browser in headed mode", false).option("-m, --model <model>", "AI model to use").option("--parallel <n>", "Number of parallel browsers", "1").option("--json", "Output results as JSON", false).option("-o, --output <filepath>", "Write JSON results to file").option("--timeout <ms>", "Timeout in milliseconds").option("--from-todos", "Import scenarios from todos before running", false).option("--project <id>", "Project ID").option("-b, --background", "Start run in background and return immediately", false).option("--browser <engine>", "Browser engine: playwright (default), lightpanda (9x faster, no screenshots), or bun (native WKWebView, 11x faster, Bun canary required)", "playwright").option("--env <name>", "Use a named environment for the URL").option("--dry-run", "Print what would run without launching browser", false).option("--retry <n>", "Retry failed scenarios up to n times", "0").option("--samples <n>", "Run each scenario N times and report flakiness (pass rate)", "1").option("--flakiness-threshold <n>", "Pass rate threshold below which a scenario is marked flaky (0-1)", "0.95").option("--a11y [level]", "Run axe-core WCAG accessibility scan after each navigation (level: A, AA, AAA \u2014 default AA)").option("--self-heal", "Enable AI-powered selector repair when elements can't be found (requires judgeModel or ANTHROPIC_API_KEY)", false).option("--verbose", "Show per-step timing and full tool results", false).option("--watch-results", "When used with --background, poll and display live results table until run completes", false).option("--failed-only", "Only show failed/error scenarios in output (passed count shown as summary)", false).option("--smoke", "Run only smoke-tagged scenarios (fast validation suite, <2 min)", false).option("--minimal", "Fastest possible run: cheapest model, max parallelism, min turns (ideal for CI)", false).option("--github-comment", "Post pass/fail summary as a GitHub PR comment (requires GITHUB_TOKEN env var)", false).option("--pr <number>", "GitHub PR number (auto-detected from GITHUB_REF if not provided)").option("--persona <id>", "Override persona for this run (comma-separated IDs for divergence testing)").option("--max-cost <dollars>", "Hard budget cap in dollars \u2014 abort if estimated cost exceeds this (e.g. 0.50 for 50 cents)").option("--cache-max-age <seconds>", "Skip scenarios that passed at the same URL within this many seconds (0 = disabled)", "0").option("--diff", "Auto-detect changed files from git diff and run only relevant scenarios", false).option("--auto-generate", "If no scenarios exist, crawl the URL and generate scenarios automatically (enabled by default when a URL is given as the first arg)").option("--no-auto-generate", "Disable automatic scenario generation when no scenarios exist").option("--overall-timeout <ms>", "Hard overall timeout for the whole run in milliseconds (default 10 minutes)").option("-y, --yes", "Skip confirmation prompts (e.g. proceed past budget warnings)", false).action(async (urlArg, description, opts) => {
|
|
97555
|
+
}, []).option("-s, --scenario <id>", "Run specific scenario ID").option("-p, --priority <level>", "Filter by priority").option("--headed", "Run browser in headed mode", false).option("-m, --model <model>", "AI model to use").option("--parallel <n>", "Number of parallel browsers", "1").option("--json", "Output results as JSON", false).option("-o, --output <filepath>", "Write JSON results to file").option("--timeout <ms>", "Timeout in milliseconds").option("--from-todos", "Import scenarios from todos before running", false).option("--project <id>", "Project ID").option("-b, --background", "Start run in background and return immediately", false).option("--browser <engine>", "Browser engine: playwright (default), lightpanda (9x faster, no screenshots), or bun (native WKWebView, 11x faster, Bun canary required)", "playwright").option("--env <name>", "Use a named environment for the URL").option("--dry-run", "Print what would run without launching browser", false).option("--retry <n>", "Retry failed scenarios up to n times", "0").option("--samples <n>", "Run each scenario N times and report flakiness (pass rate)", "1").option("--flakiness-threshold <n>", "Pass rate threshold below which a scenario is marked flaky (0-1)", "0.95").option("--a11y [level]", "Run axe-core WCAG accessibility scan after each navigation (level: A, AA, AAA \u2014 default AA)").option("--self-heal", "Enable AI-powered selector repair when elements can't be found (requires judgeModel or ANTHROPIC_API_KEY)", false).option("--verbose", "Show per-step timing and full tool results", false).option("--watch-results", "When used with --background, poll and display live results table until run completes", false).option("--failed-only", "Only show failed/error scenarios in output (passed count shown as summary)", false).option("--smoke", "Run only smoke-tagged scenarios (fast validation suite, <2 min)", false).option("--minimal", "Fastest possible run: cheapest model, max parallelism, min turns (ideal for CI)", false).option("--max-turns <n>", "Maximum AI browser-agent turns before reporting an error").option("--github-comment", "Post pass/fail summary as a GitHub PR comment (requires GITHUB_TOKEN env var)", false).option("--pr <number>", "GitHub PR number (auto-detected from GITHUB_REF if not provided)").option("--persona <id>", "Override persona for this run (comma-separated IDs for divergence testing)").option("--max-cost <dollars>", "Hard budget cap in dollars \u2014 abort if estimated cost exceeds this (e.g. 0.50 for 50 cents)").option("--cache-max-age <seconds>", "Skip scenarios that passed at the same URL within this many seconds (0 = disabled)", "0").option("--diff", "Auto-detect changed files from git diff and run only relevant scenarios", false).option("--auto-generate", "If no scenarios exist, crawl the URL and generate scenarios automatically (enabled by default when a URL is given as the first arg)").option("--no-auto-generate", "Disable automatic scenario generation when no scenarios exist").option("--overall-timeout <ms>", "Hard overall timeout for the whole run in milliseconds (default 10 minutes)").option("-y, --yes", "Skip confirmation prompts (e.g. proceed past budget warnings)", false).action(async (urlArg, description, opts) => {
|
|
97480
97556
|
try {
|
|
97481
97557
|
const projectId = resolveProject2(opts.project);
|
|
97482
97558
|
let url2 = urlArg;
|
|
@@ -97626,6 +97702,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97626
97702
|
headed: opts.headed,
|
|
97627
97703
|
parallel: parseInt(opts.parallel, 10),
|
|
97628
97704
|
timeout: opts.timeout ? parseInt(opts.timeout, 10) : undefined,
|
|
97705
|
+
maxTurns: opts.maxTurns ? parseInt(opts.maxTurns, 10) : undefined,
|
|
97629
97706
|
projectId,
|
|
97630
97707
|
engine: opts.browser
|
|
97631
97708
|
});
|
|
@@ -97744,6 +97821,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97744
97821
|
headed: opts.headed,
|
|
97745
97822
|
parallel: parseInt(opts.parallel, 10),
|
|
97746
97823
|
timeout: opts.timeout ? parseInt(opts.timeout, 10) : undefined,
|
|
97824
|
+
maxTurns: opts.maxTurns ? parseInt(opts.maxTurns, 10) : undefined,
|
|
97747
97825
|
retry: parseInt(opts.retry ?? "0", 10),
|
|
97748
97826
|
projectId,
|
|
97749
97827
|
engine: opts.browser,
|
|
@@ -97848,6 +97926,7 @@ program2.command("run [url] [description]").alias("test").description("Run test
|
|
|
97848
97926
|
headed: opts.headed,
|
|
97849
97927
|
parallel: parseInt(opts.parallel, 10),
|
|
97850
97928
|
timeout: opts.timeout ? parseInt(opts.timeout, 10) : undefined,
|
|
97929
|
+
maxTurns: opts.maxTurns ? parseInt(opts.maxTurns, 10) : undefined,
|
|
97851
97930
|
retry: parseInt(opts.retry ?? "0", 10),
|
|
97852
97931
|
projectId,
|
|
97853
97932
|
engine: opts.browser,
|
|
@@ -99145,7 +99224,7 @@ program2.command("quick-qa <url>").alias("quick-check").description("Run a fast
|
|
|
99145
99224
|
}, []).option("--max-pages <n>", "Max pages to crawl for link checks", "20").option("--skip <check>", "Skip a check: console|network|links|perf|smoke|a11y (repeatable)", (v2, acc) => {
|
|
99146
99225
|
acc.push(v2);
|
|
99147
99226
|
return acc;
|
|
99148
|
-
}, []).option("--a11y [level]", "Include WCAG accessibility scan at A, AA, or AAA (default AA)").option("--no-smoke", "Skip autonomous smoke exploration").option("-m, --model <model>", "AI model for autonomous smoke", "quick").option("--headed", "Run browser checks in headed mode", false).option("--timeout <ms>", "Navigation timeout per page in ms", "15000").option("--project <id>", "Project ID for issue tracking").option("--json", "Output results as JSON", false).option("-o, --output <file>", "Write JSON results to a file").action(async (url2, opts) => {
|
|
99227
|
+
}, []).option("--a11y [level]", "Include WCAG accessibility scan at A, AA, or AAA (default AA)").option("--no-smoke", "Skip autonomous smoke exploration").option("-m, --model <model>", "AI model for autonomous smoke", "quick").option("--headed", "Run browser checks in headed mode", false).option("--timeout <ms>", "Navigation timeout per page in ms", "15000").option("--overall-timeout <ms>", "Hard overall timeout for the quick QA run in milliseconds", String(DEFAULT_QUICK_QA_OVERALL_TIMEOUT_MS)).option("--project <id>", "Project ID for issue tracking").option("--json", "Output results as JSON", false).option("-o, --output <file>", "Write JSON results to a file").action(async (url2, opts) => {
|
|
99149
99228
|
try {
|
|
99150
99229
|
const projectId = resolveProject2(opts.project);
|
|
99151
99230
|
const includeA11y = opts.a11y !== undefined;
|
|
@@ -99166,6 +99245,7 @@ program2.command("quick-qa <url>").alias("quick-check").description("Run a fast
|
|
|
99166
99245
|
projectId,
|
|
99167
99246
|
headed: opts.headed,
|
|
99168
99247
|
timeoutMs: parseInt(opts.timeout, 10),
|
|
99248
|
+
overallTimeoutMs: parseInt(opts.overallTimeout, 10),
|
|
99169
99249
|
maxPages: parseInt(opts.maxPages, 10),
|
|
99170
99250
|
scanners: selection.scanners,
|
|
99171
99251
|
includeSmoke: selection.includeSmoke,
|
package/dist/index.js
CHANGED
|
@@ -16452,6 +16452,14 @@ function emit(event) {
|
|
|
16452
16452
|
function resolveAgentApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
16453
16453
|
return resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey);
|
|
16454
16454
|
}
|
|
16455
|
+
function resolveAgentMaxTurns(options) {
|
|
16456
|
+
if (options.maxTurns !== undefined) {
|
|
16457
|
+
const parsed = Math.floor(options.maxTurns);
|
|
16458
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
16459
|
+
return parsed;
|
|
16460
|
+
}
|
|
16461
|
+
return options.minimal ? 10 : 30;
|
|
16462
|
+
}
|
|
16455
16463
|
function assertionDescription(result) {
|
|
16456
16464
|
return result.assertion.description || `${result.assertion.type}${result.assertion.selector ? ` ${result.assertion.selector}` : ""}`;
|
|
16457
16465
|
}
|
|
@@ -16671,7 +16679,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
16671
16679
|
runId,
|
|
16672
16680
|
sessionId: result.id,
|
|
16673
16681
|
baseUrl: options.url,
|
|
16674
|
-
maxTurns: effectiveOptions
|
|
16682
|
+
maxTurns: resolveAgentMaxTurns(effectiveOptions),
|
|
16675
16683
|
a11y: effectiveOptions.a11y,
|
|
16676
16684
|
persona: persona ? {
|
|
16677
16685
|
name: persona.name,
|
|
@@ -19135,6 +19143,7 @@ async function notifyHealthScan(url, counts) {
|
|
|
19135
19143
|
}
|
|
19136
19144
|
|
|
19137
19145
|
// src/lib/quick-qa.ts
|
|
19146
|
+
var DEFAULT_QUICK_QA_OVERALL_TIMEOUT_MS = 120000;
|
|
19138
19147
|
var DEFAULT_QUICK_QA_SCANNERS = [
|
|
19139
19148
|
"console",
|
|
19140
19149
|
"network",
|
|
@@ -19185,7 +19194,17 @@ function resolveQuickQaSelection(options = {}) {
|
|
|
19185
19194
|
}
|
|
19186
19195
|
async function runQuickQa(options) {
|
|
19187
19196
|
const start = Date.now();
|
|
19188
|
-
const
|
|
19197
|
+
const timeoutMs = options.overallTimeoutMs ?? DEFAULT_QUICK_QA_OVERALL_TIMEOUT_MS;
|
|
19198
|
+
return withQuickQaTimeout(runQuickQaUnbounded(options, start), {
|
|
19199
|
+
url: options.url,
|
|
19200
|
+
start,
|
|
19201
|
+
timeoutMs
|
|
19202
|
+
});
|
|
19203
|
+
}
|
|
19204
|
+
async function runQuickQaUnbounded(options, start) {
|
|
19205
|
+
const healthScanner = options.healthScanner ?? runHealthScan;
|
|
19206
|
+
const smokeRunner = options.smokeRunner ?? runSmoke;
|
|
19207
|
+
const health = await healthScanner({
|
|
19189
19208
|
url: options.url,
|
|
19190
19209
|
pages: options.pages,
|
|
19191
19210
|
projectId: options.projectId,
|
|
@@ -19195,7 +19214,7 @@ async function runQuickQa(options) {
|
|
|
19195
19214
|
maxPages: options.maxPages,
|
|
19196
19215
|
wcagLevel: options.wcagLevel
|
|
19197
19216
|
});
|
|
19198
|
-
const smoke = options.includeSmoke === false ? null : await
|
|
19217
|
+
const smoke = options.includeSmoke === false ? null : await smokeRunner({
|
|
19199
19218
|
url: options.url,
|
|
19200
19219
|
model: options.model,
|
|
19201
19220
|
headed: options.headed,
|
|
@@ -19209,6 +19228,62 @@ async function runQuickQa(options) {
|
|
|
19209
19228
|
durationMs: Date.now() - start
|
|
19210
19229
|
});
|
|
19211
19230
|
}
|
|
19231
|
+
function withQuickQaTimeout(promise, options) {
|
|
19232
|
+
if (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)
|
|
19233
|
+
return promise;
|
|
19234
|
+
return new Promise((resolve, reject) => {
|
|
19235
|
+
const timer = setTimeout(() => {
|
|
19236
|
+
resolve(buildQuickQaTimeoutResult({
|
|
19237
|
+
url: options.url,
|
|
19238
|
+
start: options.start,
|
|
19239
|
+
timeoutMs: options.timeoutMs
|
|
19240
|
+
}));
|
|
19241
|
+
}, options.timeoutMs);
|
|
19242
|
+
promise.then((result) => {
|
|
19243
|
+
clearTimeout(timer);
|
|
19244
|
+
resolve(result);
|
|
19245
|
+
}, (error) => {
|
|
19246
|
+
clearTimeout(timer);
|
|
19247
|
+
reject(error);
|
|
19248
|
+
});
|
|
19249
|
+
});
|
|
19250
|
+
}
|
|
19251
|
+
function buildQuickQaTimeoutResult(input) {
|
|
19252
|
+
const now2 = new Date;
|
|
19253
|
+
const durationMs = Math.max(0, Date.now() - input.start);
|
|
19254
|
+
const message = `Quick QA timed out after ${input.timeoutMs}ms before all checks finished. Increase --overall-timeout or skip slow checks.`;
|
|
19255
|
+
const health = {
|
|
19256
|
+
url: input.url,
|
|
19257
|
+
scannedAt: now2.toISOString(),
|
|
19258
|
+
durationMs,
|
|
19259
|
+
totalIssues: 1,
|
|
19260
|
+
newIssues: 1,
|
|
19261
|
+
regressedIssues: 0,
|
|
19262
|
+
existingIssues: 0,
|
|
19263
|
+
results: [{
|
|
19264
|
+
url: input.url,
|
|
19265
|
+
pages: [input.url],
|
|
19266
|
+
scannedAt: now2.toISOString(),
|
|
19267
|
+
durationMs,
|
|
19268
|
+
issues: [{
|
|
19269
|
+
type: "performance",
|
|
19270
|
+
severity: "high",
|
|
19271
|
+
pageUrl: input.url,
|
|
19272
|
+
message,
|
|
19273
|
+
detail: {
|
|
19274
|
+
check: "quick-qa",
|
|
19275
|
+
timeoutMs: input.timeoutMs
|
|
19276
|
+
}
|
|
19277
|
+
}]
|
|
19278
|
+
}]
|
|
19279
|
+
};
|
|
19280
|
+
return buildQuickQaResult({
|
|
19281
|
+
url: input.url,
|
|
19282
|
+
health,
|
|
19283
|
+
smoke: null,
|
|
19284
|
+
durationMs
|
|
19285
|
+
});
|
|
19286
|
+
}
|
|
19212
19287
|
function buildQuickQaResult(input) {
|
|
19213
19288
|
const healthActionable = input.health.newIssues + input.health.regressedIssues;
|
|
19214
19289
|
const smokeIssues = input.smoke?.issuesFound.length ?? 0;
|
package/dist/lib/quick-qa.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { type HealthScanOptions, type HealthScanSummary } from "./health-scan.js";
|
|
2
|
-
import { type SmokeResult } from "./smoke.js";
|
|
1
|
+
import { runHealthScan, type HealthScanOptions, type HealthScanSummary } from "./health-scan.js";
|
|
2
|
+
import { runSmoke, type SmokeResult } from "./smoke.js";
|
|
3
3
|
export type QuickQaScanner = NonNullable<HealthScanOptions["scanners"]>[number];
|
|
4
4
|
export type QuickQaSkipTarget = QuickQaScanner | "smoke";
|
|
5
5
|
export type QuickQaStatus = "passed" | "warn" | "failed";
|
|
6
|
+
export declare const DEFAULT_QUICK_QA_OVERALL_TIMEOUT_MS = 120000;
|
|
6
7
|
export declare const DEFAULT_QUICK_QA_SCANNERS: QuickQaScanner[];
|
|
7
8
|
export interface QuickQaSelection {
|
|
8
9
|
scanners: QuickQaScanner[];
|
|
@@ -15,11 +16,14 @@ export interface QuickQaOptions {
|
|
|
15
16
|
projectId?: string;
|
|
16
17
|
headed?: boolean;
|
|
17
18
|
timeoutMs?: number;
|
|
19
|
+
overallTimeoutMs?: number;
|
|
18
20
|
maxPages?: number;
|
|
19
21
|
scanners?: QuickQaScanner[];
|
|
20
22
|
includeSmoke?: boolean;
|
|
21
23
|
model?: string;
|
|
22
24
|
wcagLevel?: "A" | "AA" | "AAA";
|
|
25
|
+
healthScanner?: typeof runHealthScan;
|
|
26
|
+
smokeRunner?: typeof runSmoke;
|
|
23
27
|
}
|
|
24
28
|
export interface QuickQaCheckSummary {
|
|
25
29
|
name: "health" | "smoke";
|
|
@@ -50,6 +54,11 @@ export declare function resolveQuickQaSelection(options?: {
|
|
|
50
54
|
scanners?: QuickQaScanner[];
|
|
51
55
|
}): QuickQaSelection;
|
|
52
56
|
export declare function runQuickQa(options: QuickQaOptions): Promise<QuickQaResult>;
|
|
57
|
+
export declare function buildQuickQaTimeoutResult(input: {
|
|
58
|
+
url: string;
|
|
59
|
+
start: number;
|
|
60
|
+
timeoutMs: number;
|
|
61
|
+
}): QuickQaResult;
|
|
53
62
|
export declare function buildQuickQaResult(input: {
|
|
54
63
|
url: string;
|
|
55
64
|
health: HealthScanSummary;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quick-qa.d.ts","sourceRoot":"","sources":["../../src/lib/quick-qa.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"quick-qa.d.ts","sourceRoot":"","sources":["../../src/lib/quick-qa.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/runner.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export interface RunOptions {
|
|
|
23
23
|
skipBudgetCheck?: boolean;
|
|
24
24
|
cacheMaxAgeMs?: number;
|
|
25
25
|
minimal?: boolean;
|
|
26
|
+
maxTurns?: number;
|
|
26
27
|
recordVideo?: boolean;
|
|
27
28
|
}
|
|
28
29
|
export interface RunEvent {
|
|
@@ -47,6 +48,7 @@ export interface RunEvent {
|
|
|
47
48
|
export type RunEventHandler = (event: RunEvent) => void;
|
|
48
49
|
export declare function onRunEvent(handler: RunEventHandler): void;
|
|
49
50
|
export declare function resolveAgentApiKeyForModel(model: string, explicitApiKey?: string, configuredAnthropicApiKey?: string): string | undefined;
|
|
51
|
+
export declare function resolveAgentMaxTurns(options: Pick<RunOptions, "minimal" | "maxTurns">): number;
|
|
50
52
|
type AgentScenarioStatus = Extract<ResultStatus, "passed" | "failed" | "error">;
|
|
51
53
|
export interface StructuredAssertionOutcome {
|
|
52
54
|
status: AgentScenarioStatus;
|
package/dist/lib/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "@hasna/testers",
|
|
55
|
-
version: "0.0.
|
|
55
|
+
version: "0.0.38",
|
|
56
56
|
description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
|
|
57
57
|
type: "module",
|
|
58
58
|
main: "dist/index.js",
|
|
@@ -21180,6 +21180,7 @@ __export(exports_runner, {
|
|
|
21180
21180
|
runByFilter: () => runByFilter,
|
|
21181
21181
|
runBatch: () => runBatch,
|
|
21182
21182
|
resolveScenariosForRun: () => resolveScenariosForRun,
|
|
21183
|
+
resolveAgentMaxTurns: () => resolveAgentMaxTurns,
|
|
21183
21184
|
resolveAgentApiKeyForModel: () => resolveAgentApiKeyForModel,
|
|
21184
21185
|
onRunEvent: () => onRunEvent,
|
|
21185
21186
|
applyStructuredAssertionsToResult: () => applyStructuredAssertionsToResult
|
|
@@ -21197,6 +21198,14 @@ function emit(event) {
|
|
|
21197
21198
|
function resolveAgentApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
21198
21199
|
return resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey);
|
|
21199
21200
|
}
|
|
21201
|
+
function resolveAgentMaxTurns(options) {
|
|
21202
|
+
if (options.maxTurns !== undefined) {
|
|
21203
|
+
const parsed = Math.floor(options.maxTurns);
|
|
21204
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
21205
|
+
return parsed;
|
|
21206
|
+
}
|
|
21207
|
+
return options.minimal ? 10 : 30;
|
|
21208
|
+
}
|
|
21200
21209
|
function assertionDescription(result) {
|
|
21201
21210
|
return result.assertion.description || `${result.assertion.type}${result.assertion.selector ? ` ${result.assertion.selector}` : ""}`;
|
|
21202
21211
|
}
|
|
@@ -21416,7 +21425,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
21416
21425
|
runId,
|
|
21417
21426
|
sessionId: result.id,
|
|
21418
21427
|
baseUrl: options.url,
|
|
21419
|
-
maxTurns: effectiveOptions
|
|
21428
|
+
maxTurns: resolveAgentMaxTurns(effectiveOptions),
|
|
21420
21429
|
a11y: effectiveOptions.a11y,
|
|
21421
21430
|
persona: persona ? {
|
|
21422
21431
|
name: persona.name,
|
package/dist/server/index.js
CHANGED
|
@@ -46910,7 +46910,7 @@ import { join as join14 } from "path";
|
|
|
46910
46910
|
// package.json
|
|
46911
46911
|
var package_default = {
|
|
46912
46912
|
name: "@hasna/testers",
|
|
46913
|
-
version: "0.0.
|
|
46913
|
+
version: "0.0.38",
|
|
46914
46914
|
description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
|
|
46915
46915
|
type: "module",
|
|
46916
46916
|
main: "dist/index.js",
|
|
@@ -49404,6 +49404,14 @@ function emit(event) {
|
|
|
49404
49404
|
function resolveAgentApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey) {
|
|
49405
49405
|
return resolveProviderApiKeyForModel(model, explicitApiKey, configuredAnthropicApiKey);
|
|
49406
49406
|
}
|
|
49407
|
+
function resolveAgentMaxTurns(options) {
|
|
49408
|
+
if (options.maxTurns !== undefined) {
|
|
49409
|
+
const parsed = Math.floor(options.maxTurns);
|
|
49410
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
49411
|
+
return parsed;
|
|
49412
|
+
}
|
|
49413
|
+
return options.minimal ? 10 : 30;
|
|
49414
|
+
}
|
|
49407
49415
|
function assertionDescription(result) {
|
|
49408
49416
|
return result.assertion.description || `${result.assertion.type}${result.assertion.selector ? ` ${result.assertion.selector}` : ""}`;
|
|
49409
49417
|
}
|
|
@@ -49623,7 +49631,7 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
49623
49631
|
runId,
|
|
49624
49632
|
sessionId: result.id,
|
|
49625
49633
|
baseUrl: options.url,
|
|
49626
|
-
maxTurns: effectiveOptions
|
|
49634
|
+
maxTurns: resolveAgentMaxTurns(effectiveOptions),
|
|
49627
49635
|
a11y: effectiveOptions.a11y,
|
|
49628
49636
|
persona: persona ? {
|
|
49629
49637
|
name: persona.name,
|