@qa-ai-stlc/cli 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +66 -7
- package/dist/cli.js.map +1 -1
- package/dist/command-context.d.ts +3 -1
- package/dist/command-context.d.ts.map +1 -1
- package/dist/command-context.js +2 -1
- package/dist/command-context.js.map +1 -1
- package/dist/commands/explore.d.ts +35 -0
- package/dist/commands/explore.d.ts.map +1 -0
- package/dist/commands/explore.js +247 -0
- package/dist/commands/explore.js.map +1 -0
- package/dist/package-version.d.ts +3 -0
- package/dist/package-version.d.ts.map +1 -0
- package/dist/package-version.js +10 -0
- package/dist/package-version.js.map +1 -0
- package/package.json +7 -6
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAwB,KAAK,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAO9F,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,2BAA2B,EAAE,aAAa,GAAG,MAAM,CAAC,GAAG;IAC3F,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAcF;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,YAAY,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BvG"}
|
package/dist/cli.js
CHANGED
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
// Copyright The QA-AI-STLC Authors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { createRequire } from 'node:module';
|
|
4
3
|
import { parseArgs } from 'node:util';
|
|
5
4
|
import { QaError } from '@qa-ai-stlc/core';
|
|
6
5
|
import { createCommandContext } from './command-context.js';
|
|
7
6
|
import { runDoctor } from './commands/doctor.js';
|
|
7
|
+
import { runExplore } from './commands/explore.js';
|
|
8
8
|
import { runInit } from './commands/init.js';
|
|
9
9
|
import { EXIT_FAILURE, EXIT_SUCCESS, EXIT_USAGE } from './exit-codes.js';
|
|
10
|
+
import { readPackageVersion } from './package-version.js';
|
|
10
11
|
const USAGE = `Usage: qa <command> [options]
|
|
11
12
|
|
|
12
13
|
Commands:
|
|
13
14
|
init Create the .qa/ store and a starting config.yaml
|
|
14
15
|
doctor Check Node, browsers, identities and environment reachability
|
|
16
|
+
explore Build the selector registry: crawl, static source analysis, pick mode, --verify
|
|
15
17
|
|
|
16
18
|
Global options:
|
|
17
19
|
--json Print machine-readable JSON instead of human text
|
|
18
20
|
-h, --help Show this help
|
|
19
21
|
--version Show the CLI version`;
|
|
20
|
-
function readCliVersion() {
|
|
21
|
-
const require = createRequire(import.meta.url);
|
|
22
|
-
const packageJson = require('../package.json');
|
|
23
|
-
return packageJson.version;
|
|
24
|
-
}
|
|
25
22
|
/**
|
|
26
23
|
* Parses argv and dispatches to a command, returning the process exit code (AGENTS.md 5.4:
|
|
27
24
|
* `process.exit` itself belongs only in the bin entry point). Never throws: an unexpected error
|
|
@@ -35,7 +32,7 @@ export async function runCli(argv, dependencies) {
|
|
|
35
32
|
return command === undefined ? EXIT_USAGE : EXIT_SUCCESS;
|
|
36
33
|
}
|
|
37
34
|
if (command === '--version') {
|
|
38
|
-
io.stdout(
|
|
35
|
+
io.stdout(readPackageVersion());
|
|
39
36
|
return EXIT_SUCCESS;
|
|
40
37
|
}
|
|
41
38
|
try {
|
|
@@ -44,6 +41,8 @@ export async function runCli(argv, dependencies) {
|
|
|
44
41
|
return await dispatchInit(rest, dependencies);
|
|
45
42
|
case 'doctor':
|
|
46
43
|
return await dispatchDoctor(rest, dependencies);
|
|
44
|
+
case 'explore':
|
|
45
|
+
return await dispatchExplore(rest, dependencies);
|
|
47
46
|
default:
|
|
48
47
|
io.stderr(`Unknown command "${command}".\n\n${USAGE}`);
|
|
49
48
|
return EXIT_USAGE;
|
|
@@ -108,6 +107,46 @@ async function dispatchDoctor(rest, dependencies) {
|
|
|
108
107
|
printResult(context.io, json, 'doctor', report, formatDoctorReport(report));
|
|
109
108
|
return report.ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
110
109
|
}
|
|
110
|
+
function parsePositiveInt(value, flag) {
|
|
111
|
+
const parsed = Number.parseInt(value, 10);
|
|
112
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
113
|
+
throw new QaError('EXPLORE_OPTION_INVALID', `"${value}" is not a positive integer for ${flag}`);
|
|
114
|
+
}
|
|
115
|
+
return parsed;
|
|
116
|
+
}
|
|
117
|
+
async function dispatchExplore(rest, dependencies) {
|
|
118
|
+
const values = parseCommandArgs(rest, {
|
|
119
|
+
json: { type: 'boolean', default: false },
|
|
120
|
+
environment: { type: 'string' },
|
|
121
|
+
identity: { type: 'string' },
|
|
122
|
+
'cdp-endpoint': { type: 'string' },
|
|
123
|
+
policy: { type: 'string' },
|
|
124
|
+
static: { type: 'boolean', default: false },
|
|
125
|
+
pick: { type: 'string' },
|
|
126
|
+
'max-pages': { type: 'string' },
|
|
127
|
+
verify: { type: 'boolean', default: false },
|
|
128
|
+
});
|
|
129
|
+
const json = values.json === true;
|
|
130
|
+
const context = createCommandContext({
|
|
131
|
+
...dependencies,
|
|
132
|
+
projectRoot: dependencies.projectRoot ?? process.cwd(),
|
|
133
|
+
json,
|
|
134
|
+
});
|
|
135
|
+
const report = await runExplore(context, {
|
|
136
|
+
...(typeof values.environment === 'string' ? { environment: values.environment } : {}),
|
|
137
|
+
...(typeof values.identity === 'string' ? { identity: values.identity } : {}),
|
|
138
|
+
...(typeof values['cdp-endpoint'] === 'string' ? { cdpEndpointUrl: values['cdp-endpoint'] } : {}),
|
|
139
|
+
...(typeof values.policy === 'string' ? { policy: values.policy } : {}),
|
|
140
|
+
static: values.static === true,
|
|
141
|
+
...(typeof values.pick === 'string' ? { pick: values.pick } : {}),
|
|
142
|
+
...(typeof values['max-pages'] === 'string'
|
|
143
|
+
? { maxPages: parsePositiveInt(values['max-pages'], '--max-pages') }
|
|
144
|
+
: {}),
|
|
145
|
+
verify: values.verify === true,
|
|
146
|
+
});
|
|
147
|
+
printResult(context.io, json, 'explore', report, formatExploreReport(report));
|
|
148
|
+
return report.degraded.length > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
149
|
+
}
|
|
111
150
|
function printResult(io, json, command, data, humanLines) {
|
|
112
151
|
if (json) {
|
|
113
152
|
io.stdout(JSON.stringify({ command, data }));
|
|
@@ -130,4 +169,24 @@ function formatDoctorReport(report) {
|
|
|
130
169
|
return `[${marker}] ${check.name}: ${check.message}${remediation}`;
|
|
131
170
|
});
|
|
132
171
|
}
|
|
172
|
+
function formatExploreReport(report) {
|
|
173
|
+
if (report.mode === 'verify') {
|
|
174
|
+
const lines = [`Verified ${report.registryPath}: ${String(report.elementCount)} element(s) checked.`];
|
|
175
|
+
if (report.degraded.length === 0) {
|
|
176
|
+
lines.push('No degraded selectors.');
|
|
177
|
+
return lines;
|
|
178
|
+
}
|
|
179
|
+
lines.push(`${String(report.degraded.length)} degraded selector(s):`);
|
|
180
|
+
for (const element of report.degraded) {
|
|
181
|
+
lines.push(` ${element.elementId}: ${String(element.previousScore)} -> ${String(element.currentScore)}`);
|
|
182
|
+
}
|
|
183
|
+
return lines;
|
|
184
|
+
}
|
|
185
|
+
return [
|
|
186
|
+
`Wrote ${report.registryPath}: ${String(report.elementCount)} element(s) (` +
|
|
187
|
+
`${String(report.added)} added, ${String(report.removed)} removed, ${String(report.degraded.length)} degraded).`,
|
|
188
|
+
`${String(report.missingLocatorCount)} element(s) with no locator candidate.`,
|
|
189
|
+
`${String(report.blockedRequestCount)} non-GET request(s) blocked by safe mode.`,
|
|
190
|
+
];
|
|
191
|
+
}
|
|
133
192
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAEtC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Clock, type FileSystem, type HttpClient, type Logger, type ProcessRunner } from '@qa-ai-stlc/core';
|
|
1
|
+
import { type BrowserLauncher, type Clock, type FileSystem, type HttpClient, type Logger, type ProcessRunner } from '@qa-ai-stlc/core';
|
|
2
2
|
import type { CliIO } from './cli-io.js';
|
|
3
3
|
/**
|
|
4
4
|
* Everything a command needs, injected so commands are testable without real I/O, a real clock
|
|
@@ -14,6 +14,7 @@ export interface CommandContext {
|
|
|
14
14
|
readonly logger: Logger;
|
|
15
15
|
readonly processRunner: ProcessRunner;
|
|
16
16
|
readonly httpClient: HttpClient;
|
|
17
|
+
readonly browserLauncher: BrowserLauncher;
|
|
17
18
|
readonly env: Readonly<Record<string, string | undefined>>;
|
|
18
19
|
}
|
|
19
20
|
export interface CreateCommandContextOptions {
|
|
@@ -25,6 +26,7 @@ export interface CreateCommandContextOptions {
|
|
|
25
26
|
readonly logger?: Logger;
|
|
26
27
|
readonly processRunner?: ProcessRunner;
|
|
27
28
|
readonly httpClient?: HttpClient;
|
|
29
|
+
readonly browserLauncher?: BrowserLauncher;
|
|
28
30
|
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
29
31
|
}
|
|
30
32
|
export declare function createCommandContext(options: CreateCommandContextOptions): CommandContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-context.d.ts","sourceRoot":"","sources":["../src/command-context.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"command-context.d.ts","sourceRoot":"","sources":["../src/command-context.ts"],"names":[],"mappings":"AAGA,OAAO,EAOL,KAAK,eAAe,EACpB,KAAK,KAAK,EACV,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;CAC7D;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,cAAc,CAazF"}
|
package/dist/command-context.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright The QA-AI-STLC Authors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { fetchHttpClient, nodeFileSystem, nodeProcessRunner, noopLogger, systemClock, } from '@qa-ai-stlc/core';
|
|
3
|
+
import { fetchHttpClient, nodeFileSystem, nodeProcessRunner, noopLogger, playwrightBrowserLauncher, systemClock, } from '@qa-ai-stlc/core';
|
|
4
4
|
export function createCommandContext(options) {
|
|
5
5
|
return {
|
|
6
6
|
projectRoot: options.projectRoot,
|
|
@@ -11,6 +11,7 @@ export function createCommandContext(options) {
|
|
|
11
11
|
logger: options.logger ?? noopLogger,
|
|
12
12
|
processRunner: options.processRunner ?? nodeProcessRunner,
|
|
13
13
|
httpClient: options.httpClient ?? fetchHttpClient,
|
|
14
|
+
browserLauncher: options.browserLauncher ?? playwrightBrowserLauncher,
|
|
14
15
|
env: options.env ?? process.env,
|
|
15
16
|
};
|
|
16
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-context.js","sourceRoot":"","sources":["../src/command-context.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAEtC,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,WAAW,
|
|
1
|
+
{"version":3,"file":"command-context.js","sourceRoot":"","sources":["../src/command-context.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAEtC,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,yBAAyB,EACzB,WAAW,GAOZ,MAAM,kBAAkB,CAAC;AAkC1B,MAAM,UAAU,oBAAoB,CAAC,OAAoC;IACvE,OAAO;QACL,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,KAAK;QAC3B,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,cAAc;QAChC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,WAAW;QACnC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,UAAU;QACpC,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,iBAAiB;QACzD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,eAAe;QACjD,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,yBAAyB;QACrE,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG;KAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type DegradedSelectorElement } from '@qa-ai-stlc/explorer';
|
|
2
|
+
import type { CommandContext } from '../command-context.js';
|
|
3
|
+
export interface ExploreOptions {
|
|
4
|
+
readonly environment?: string;
|
|
5
|
+
readonly identity?: string;
|
|
6
|
+
readonly cdpEndpointUrl?: string;
|
|
7
|
+
readonly policy?: string;
|
|
8
|
+
readonly static?: boolean;
|
|
9
|
+
/** A single URL to run pick mode against instead of crawling. */
|
|
10
|
+
readonly pick?: string;
|
|
11
|
+
readonly maxPages?: number;
|
|
12
|
+
/** Re-checks the stored registry's candidates live instead of building a new one. */
|
|
13
|
+
readonly verify?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface ExploreReport {
|
|
16
|
+
readonly mode: 'explore' | 'verify';
|
|
17
|
+
readonly registryPath: string;
|
|
18
|
+
readonly elementCount: number;
|
|
19
|
+
readonly added: number;
|
|
20
|
+
readonly removed: number;
|
|
21
|
+
readonly degraded: readonly DegradedSelectorElement[];
|
|
22
|
+
readonly missingLocatorCount: number;
|
|
23
|
+
readonly blockedRequestCount: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* `qa explore`: builds the selector registry (development plan section 6.3) by crawling, then
|
|
27
|
+
* merges in static source analysis (`--static`) or a manual pick-mode session (`--pick <url>`)
|
|
28
|
+
* when asked, writes `.qa/selectors/registry.json`, `.qa/selectors/missing-test-ids.json` and the
|
|
29
|
+
* generated `tests/qa/locators.ts`, and registers all three in the manifest. `--verify` skips
|
|
30
|
+
* building anything: it re-checks every stored, non-deprecated element's primary candidate against
|
|
31
|
+
* the live page it was found on and fails (`degraded` non-empty) when one no longer resolves as
|
|
32
|
+
* well as it did when last recorded — the signal a stale selector (e.g. a renamed test ID) needs.
|
|
33
|
+
*/
|
|
34
|
+
export declare function runExplore(context: CommandContext, options?: ExploreOptions): Promise<ExploreReport>;
|
|
35
|
+
//# sourceMappingURL=explore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../src/commands/explore.ts"],"names":[],"mappings":"AAYA,OAAO,EAeL,KAAK,uBAAuB,EAG7B,MAAM,sBAAsB,CAAC;AAW9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAa5D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IACpC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACtD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;AA6OD;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CAuDxB"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// Copyright The QA-AI-STLC Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { ManifestStore, QaError, QaStore, loadConfig, resolveRelativePath, toRelativePath, } from '@qa-ai-stlc/core';
|
|
4
|
+
import { analyzePages, analyzeStaticSource, buildMissingTestIdReport, buildSelectorRegistry, capturePickModeElements, crawl, diffSelectorRegistry, finalizeManualSelectorEntries, generateLocatorModule, injectPickModeOverlay, mergeSelectorRegistry, resolveStorageState, scoreLocatorStability, waitForPickModeCompletion, } from '@qa-ai-stlc/explorer';
|
|
5
|
+
import { SCHEMA_VERSION, SelectorPolicySchema, SelectorRegistrySchema, } from '@qa-ai-stlc/schemas';
|
|
6
|
+
import { readPackageVersion } from '../package-version.js';
|
|
7
|
+
const REGISTRY_PATH = 'selectors/registry.json';
|
|
8
|
+
const MISSING_TEST_ID_REPORT_PATH = 'selectors/missing-test-ids.json';
|
|
9
|
+
const LOCATOR_MODULE_PATH = 'tests/qa/locators.ts';
|
|
10
|
+
// EJS is included alongside the three frameworks the development plan names (React/Angular/Vue):
|
|
11
|
+
// its templates are plain HTML, the same literal-attribute shape analyzeStaticSource looks for in
|
|
12
|
+
// any of the three, and the demo app (the only fixture this command is validated against) is
|
|
13
|
+
// server-rendered EJS.
|
|
14
|
+
const STATIC_SOURCE_EXTENSIONS = ['.tsx', '.jsx', '.ts', '.js', '.vue', '.html', '.ejs'];
|
|
15
|
+
function resolvePolicy(config, given) {
|
|
16
|
+
if (given === undefined) {
|
|
17
|
+
return config.selectors.policy;
|
|
18
|
+
}
|
|
19
|
+
const result = SelectorPolicySchema.safeParse(given);
|
|
20
|
+
if (!result.success) {
|
|
21
|
+
throw new QaError('EXPLORE_POLICY_INVALID', `"${given}" is not a known selector policy`, {
|
|
22
|
+
remediation: `Use one of: ${SelectorPolicySchema.options.join(', ')}.`,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return result.data;
|
|
26
|
+
}
|
|
27
|
+
function resolveEnvironment(config, name) {
|
|
28
|
+
const names = Object.keys(config.environments);
|
|
29
|
+
if (name !== undefined) {
|
|
30
|
+
const environment = config.environments[name];
|
|
31
|
+
if (environment === undefined) {
|
|
32
|
+
throw new QaError('EXPLORE_ENVIRONMENT_UNKNOWN', `No environment named "${name}" in config.yaml`, {
|
|
33
|
+
remediation: `Use one of: ${names.join(', ')}.`,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return { name, config: environment };
|
|
37
|
+
}
|
|
38
|
+
const [onlyEntry] = Object.entries(config.environments);
|
|
39
|
+
if (names.length === 1 && onlyEntry !== undefined) {
|
|
40
|
+
const [onlyName, onlyEnvironment] = onlyEntry;
|
|
41
|
+
return { name: onlyName, config: onlyEnvironment };
|
|
42
|
+
}
|
|
43
|
+
throw new QaError('EXPLORE_ENVIRONMENT_AMBIGUOUS', names.length === 0
|
|
44
|
+
? 'config.yaml defines no environments'
|
|
45
|
+
: 'No --environment given and config.yaml defines more than one', {
|
|
46
|
+
remediation: names.length === 0
|
|
47
|
+
? 'Add an environment to config.yaml.'
|
|
48
|
+
: `Pass --environment, one of: ${names.join(', ')}.`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function resolveIdentity(context, config, options) {
|
|
52
|
+
if (options.identity === undefined) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const identityConfig = config.identities[options.identity];
|
|
56
|
+
if (identityConfig === undefined) {
|
|
57
|
+
throw new QaError('EXPLORE_IDENTITY_UNKNOWN', `No identity named "${options.identity}" in config.yaml`, {
|
|
58
|
+
remediation: `Use one of: ${Object.keys(config.identities).join(', ')}.`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
config: identityConfig,
|
|
63
|
+
env: context.env,
|
|
64
|
+
...(options.cdpEndpointUrl !== undefined ? { cdpEndpointUrl: options.cdpEndpointUrl } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function readStaticSourceFiles(fs, projectRoot, sourcePath) {
|
|
68
|
+
const absoluteSourceDir = resolveRelativePath(projectRoot, sourcePath);
|
|
69
|
+
const absolutePaths = (await fs.listFiles(absoluteSourceDir)).filter((path) => STATIC_SOURCE_EXTENSIONS.some((extension) => path.endsWith(extension)));
|
|
70
|
+
return Promise.all(absolutePaths.map(async (absolutePath) => ({
|
|
71
|
+
filePath: toRelativePath(projectRoot, absolutePath),
|
|
72
|
+
content: await fs.readFile(absolutePath),
|
|
73
|
+
})));
|
|
74
|
+
}
|
|
75
|
+
async function runCrawlAndBuild(context, config, options) {
|
|
76
|
+
const environment = resolveEnvironment(config, options.environment);
|
|
77
|
+
const identity = resolveIdentity(context, config, options);
|
|
78
|
+
const policy = resolvePolicy(config, options.policy);
|
|
79
|
+
const crawlResult = await crawl({
|
|
80
|
+
startUrl: environment.config.baseUrl,
|
|
81
|
+
allowlist: environment.config.allowlist,
|
|
82
|
+
browserLauncher: context.browserLauncher,
|
|
83
|
+
...(identity !== undefined ? { identity } : {}),
|
|
84
|
+
...(options.maxPages !== undefined ? { maxPages: options.maxPages } : {}),
|
|
85
|
+
});
|
|
86
|
+
const urls = crawlResult.routeMap.routes.map((route) => route.url);
|
|
87
|
+
const { pageModelSet, blockedRequestCount: analyzeBlocked } = await analyzePages({
|
|
88
|
+
urls,
|
|
89
|
+
browserLauncher: context.browserLauncher,
|
|
90
|
+
...(identity !== undefined ? { identity } : {}),
|
|
91
|
+
});
|
|
92
|
+
const { registry, blockedRequestCount: buildBlocked } = await buildSelectorRegistry({
|
|
93
|
+
pageModelSet,
|
|
94
|
+
browserLauncher: context.browserLauncher,
|
|
95
|
+
...(identity !== undefined ? { identity } : {}),
|
|
96
|
+
policy,
|
|
97
|
+
});
|
|
98
|
+
const elements = [...registry.elements];
|
|
99
|
+
if (options.static === true) {
|
|
100
|
+
if (config.source === undefined) {
|
|
101
|
+
throw new QaError('EXPLORE_STATIC_SOURCE_MISSING', '--static was given but config.yaml has no source.path', {
|
|
102
|
+
remediation: 'Set source.path in config.yaml to the application checkout to scan.',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const files = await readStaticSourceFiles(context.fs, context.projectRoot, config.source.path);
|
|
106
|
+
elements.push(...analyzeStaticSource({ files, clock: context.clock }).elements);
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
elements,
|
|
110
|
+
blockedRequestCount: crawlResult.blockedRequestCount + analyzeBlocked + buildBlocked,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
async function runPickModeSession(context, config, options) {
|
|
114
|
+
const identity = resolveIdentity(context, config, options);
|
|
115
|
+
const policy = resolvePolicy(config, options.policy);
|
|
116
|
+
const storageState = await resolveStorageState(context.browserLauncher, identity);
|
|
117
|
+
const browser = await context.browserLauncher.launch();
|
|
118
|
+
try {
|
|
119
|
+
const browserContext = await browser.newContext(storageState === undefined ? {} : { storageState });
|
|
120
|
+
const page = await browserContext.newPage();
|
|
121
|
+
await page.goto(options.pick);
|
|
122
|
+
await injectPickModeOverlay(page);
|
|
123
|
+
context.io.stdout(`Pick mode: a browser window opened at ${options.pick}. Click every element to capture, then click "Finish picking".`);
|
|
124
|
+
const captures = await waitForPickModeCompletion(page);
|
|
125
|
+
const pickModeElements = await capturePickModeElements(page, options.pick, captures, { policy });
|
|
126
|
+
const generatedAt = context.clock.now().toISOString();
|
|
127
|
+
const elements = finalizeManualSelectorEntries(pickModeElements, new Map(), generatedAt);
|
|
128
|
+
return { elements, blockedRequestCount: 0 };
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
await browser.close();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function runVerify(context, store, config, options) {
|
|
135
|
+
const exists = await store.pathExists(REGISTRY_PATH);
|
|
136
|
+
if (!exists) {
|
|
137
|
+
throw new QaError('EXPLORE_NO_REGISTRY', 'No selector registry found to verify', {
|
|
138
|
+
remediation: 'Run "qa explore" first to build a registry.',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const stored = await store.readJson(REGISTRY_PATH, SelectorRegistrySchema);
|
|
142
|
+
const identity = resolveIdentity(context, config, options);
|
|
143
|
+
const storageState = await resolveStorageState(context.browserLauncher, identity);
|
|
144
|
+
const checkable = stored.elements.filter((element) => element.deprecatedAt === undefined &&
|
|
145
|
+
element.pageUrl !== undefined &&
|
|
146
|
+
element.locatorCandidates.length > 0);
|
|
147
|
+
const elementsByPageUrl = new Map();
|
|
148
|
+
for (const element of checkable) {
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style -- filtered above
|
|
150
|
+
const pageUrl = element.pageUrl;
|
|
151
|
+
const group = elementsByPageUrl.get(pageUrl);
|
|
152
|
+
if (group === undefined) {
|
|
153
|
+
elementsByPageUrl.set(pageUrl, [element]);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
group.push(element);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const degraded = [];
|
|
160
|
+
const browser = await context.browserLauncher.launch();
|
|
161
|
+
try {
|
|
162
|
+
const browserContext = await browser.newContext(storageState === undefined ? {} : { storageState });
|
|
163
|
+
const page = await browserContext.newPage();
|
|
164
|
+
for (const [pageUrl, elements] of elementsByPageUrl) {
|
|
165
|
+
await page.goto(pageUrl);
|
|
166
|
+
for (const element of elements) {
|
|
167
|
+
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style -- filtered above
|
|
168
|
+
const primary = element.locatorCandidates[0];
|
|
169
|
+
const currentScore = await scoreLocatorStability(page, primary);
|
|
170
|
+
if (currentScore < element.stabilityScore) {
|
|
171
|
+
degraded.push({
|
|
172
|
+
elementId: element.elementId,
|
|
173
|
+
previousScore: element.stabilityScore,
|
|
174
|
+
currentScore,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
await browser.close();
|
|
182
|
+
}
|
|
183
|
+
const missingLocatorCount = generateLocatorModule(stored, { generatorVersion: readPackageVersion() })
|
|
184
|
+
.missingLocators.length;
|
|
185
|
+
return {
|
|
186
|
+
mode: 'verify',
|
|
187
|
+
registryPath: REGISTRY_PATH,
|
|
188
|
+
elementCount: stored.elements.length,
|
|
189
|
+
added: 0,
|
|
190
|
+
removed: 0,
|
|
191
|
+
degraded,
|
|
192
|
+
missingLocatorCount,
|
|
193
|
+
blockedRequestCount: 0,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* `qa explore`: builds the selector registry (development plan section 6.3) by crawling, then
|
|
198
|
+
* merges in static source analysis (`--static`) or a manual pick-mode session (`--pick <url>`)
|
|
199
|
+
* when asked, writes `.qa/selectors/registry.json`, `.qa/selectors/missing-test-ids.json` and the
|
|
200
|
+
* generated `tests/qa/locators.ts`, and registers all three in the manifest. `--verify` skips
|
|
201
|
+
* building anything: it re-checks every stored, non-deprecated element's primary candidate against
|
|
202
|
+
* the live page it was found on and fails (`degraded` non-empty) when one no longer resolves as
|
|
203
|
+
* well as it did when last recorded — the signal a stale selector (e.g. a renamed test ID) needs.
|
|
204
|
+
*/
|
|
205
|
+
export async function runExplore(context, options = {}) {
|
|
206
|
+
const store = new QaStore({ projectRoot: context.projectRoot, fs: context.fs });
|
|
207
|
+
const manifest = new ManifestStore({ store, clock: context.clock });
|
|
208
|
+
const config = await loadConfig(store);
|
|
209
|
+
if (options.verify === true) {
|
|
210
|
+
return runVerify(context, store, config, options);
|
|
211
|
+
}
|
|
212
|
+
const previous = (await store.pathExists(REGISTRY_PATH))
|
|
213
|
+
? await store.readJson(REGISTRY_PATH, SelectorRegistrySchema)
|
|
214
|
+
: undefined;
|
|
215
|
+
const { elements, blockedRequestCount } = options.pick !== undefined
|
|
216
|
+
? await runPickModeSession(context, config, { ...options, pick: options.pick })
|
|
217
|
+
: await runCrawlAndBuild(context, config, options);
|
|
218
|
+
const generatedAt = context.clock.now().toISOString();
|
|
219
|
+
const fresh = { schemaVersion: SCHEMA_VERSION, generatedAt, elements };
|
|
220
|
+
const merged = previous === undefined ? fresh : mergeSelectorRegistry(previous, fresh, generatedAt);
|
|
221
|
+
await store.writeJson(REGISTRY_PATH, merged);
|
|
222
|
+
await manifest.register(REGISTRY_PATH, JSON.stringify(merged));
|
|
223
|
+
const moduleResult = generateLocatorModule(merged, { generatorVersion: readPackageVersion() });
|
|
224
|
+
await context.fs.mkdir(resolveRelativePath(context.projectRoot, 'tests/qa'));
|
|
225
|
+
await context.fs.writeFile(resolveRelativePath(context.projectRoot, LOCATOR_MODULE_PATH), moduleResult.source);
|
|
226
|
+
await manifest.register(LOCATOR_MODULE_PATH, moduleResult.source);
|
|
227
|
+
const missingTestIdReport = buildMissingTestIdReport(merged);
|
|
228
|
+
await store.writeJson(MISSING_TEST_ID_REPORT_PATH, missingTestIdReport);
|
|
229
|
+
await manifest.register(MISSING_TEST_ID_REPORT_PATH, JSON.stringify(missingTestIdReport));
|
|
230
|
+
// Diffed against the fresh, unmerged registry, not the merged one: a merge always keeps an
|
|
231
|
+
// element the fresh run no longer found (deprecating it in place) rather than dropping it, so
|
|
232
|
+
// diffing the merged result would never show a "removed" element at all.
|
|
233
|
+
const diff = previous === undefined
|
|
234
|
+
? { added: fresh.elements, removed: [], degraded: [] }
|
|
235
|
+
: diffSelectorRegistry(previous, fresh);
|
|
236
|
+
return {
|
|
237
|
+
mode: 'explore',
|
|
238
|
+
registryPath: REGISTRY_PATH,
|
|
239
|
+
elementCount: merged.elements.length,
|
|
240
|
+
added: diff.added.length,
|
|
241
|
+
removed: diff.removed.length,
|
|
242
|
+
degraded: diff.degraded,
|
|
243
|
+
missingLocatorCount: moduleResult.missingLocators.length,
|
|
244
|
+
blockedRequestCount,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=explore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../../src/commands/explore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-version.d.ts","sourceRoot":"","sources":["../src/package-version.ts"],"names":[],"mappings":"AAKA,mFAAmF;AACnF,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright The QA-AI-STLC Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
/** The published version of this CLI package, read from its own `package.json`. */
|
|
5
|
+
export function readPackageVersion() {
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const packageJson = require('../package.json');
|
|
8
|
+
return packageJson.version;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=package-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-version.js","sourceRoot":"","sources":["../src/package-version.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,mFAAmF;AACnF,MAAM,UAAU,kBAAkB;IAChC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAiC,CAAC;IAC/E,OAAO,WAAW,CAAC,OAAO,CAAC;AAC7B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qa-ai-stlc/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "The qa command: init, doctor and every deterministic engine operation exposed for CI and humans.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -21,18 +21,19 @@
|
|
|
21
21
|
".": "./dist/index.js"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
|
-
"pretypecheck": "npm run build --workspace @qa-ai-stlc/schemas --workspace @qa-ai-stlc/core --workspace @qa-ai-stlc/test-utils",
|
|
24
|
+
"pretypecheck": "npm run build --workspace @qa-ai-stlc/schemas --workspace @qa-ai-stlc/core --workspace @qa-ai-stlc/explorer --workspace @qa-ai-stlc/test-utils",
|
|
25
25
|
"typecheck": "tsc --noEmit -p .",
|
|
26
|
-
"pretest": "npm run build --workspace @qa-ai-stlc/schemas --workspace @qa-ai-stlc/core --workspace @qa-ai-stlc/test-utils",
|
|
26
|
+
"pretest": "npm run build --workspace @qa-ai-stlc/schemas --workspace @qa-ai-stlc/core --workspace @qa-ai-stlc/explorer --workspace @qa-ai-stlc/test-utils",
|
|
27
27
|
"test": "vitest run",
|
|
28
|
-
"pretest:coverage": "npm run build --workspace @qa-ai-stlc/schemas --workspace @qa-ai-stlc/core --workspace @qa-ai-stlc/test-utils",
|
|
28
|
+
"pretest:coverage": "npm run build --workspace @qa-ai-stlc/schemas --workspace @qa-ai-stlc/core --workspace @qa-ai-stlc/explorer --workspace @qa-ai-stlc/test-utils",
|
|
29
29
|
"test:coverage": "vitest run --coverage",
|
|
30
30
|
"build": "tsc -b tsconfig.build.json",
|
|
31
31
|
"clean": "node ../../scripts/clean-dir.mjs dist"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@qa-ai-stlc/core": "0.
|
|
35
|
-
"@qa-ai-stlc/
|
|
34
|
+
"@qa-ai-stlc/core": "0.4.0",
|
|
35
|
+
"@qa-ai-stlc/explorer": "0.5.1",
|
|
36
|
+
"@qa-ai-stlc/schemas": "0.5.0",
|
|
36
37
|
"yaml": "2.9.1"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|