@ia-qa/qa-discovery 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -5
- package/TUTORIAL.md +29 -9
- package/dist/capture/page.d.ts +10 -0
- package/dist/capture/page.js +14 -0
- package/dist/capture/page.js.map +1 -1
- package/dist/cli/args.js +2 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/generate.js +37 -1
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +13 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/login.js +29 -48
- package/dist/cli/login.js.map +1 -1
- package/dist/cli/scan.js +13 -2
- package/dist/cli/scan.js.map +1 -1
- package/dist/config.d.ts +7 -1
- package/dist/config.js +42 -2
- package/dist/config.js.map +1 -1
- package/dist/coverage.d.ts +11 -0
- package/dist/coverage.js +1 -0
- package/dist/coverage.js.map +1 -1
- package/dist/coverageView.d.ts +20 -0
- package/dist/coverageView.js +40 -1
- package/dist/coverageView.js.map +1 -1
- package/dist/generate.d.ts +33 -1
- package/dist/generate.js +46 -1
- package/dist/generate.js.map +1 -1
- package/dist/mcp/server.js +9 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/scan.d.ts +9 -0
- package/dist/scan.js +7 -7
- package/dist/scan.js.map +1 -1
- package/package.json +2 -2
- package/skills/ia-qa-discover/SKILL.md +7 -4
package/README.md
CHANGED
|
@@ -82,7 +82,12 @@ Readable index: .ia-qa-discovery/capture/_overview.md
|
|
|
82
82
|
HTML report: ia-qa-discover-report.html
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
**2. Log in by hand, once
|
|
85
|
+
**2. Log in by hand, once — and only if you have not already.** If you logged into this app
|
|
86
|
+
with `ia-qa-heal login`, there is nothing to do here: `scan` picks that session up and says
|
|
87
|
+
so. Nobody logs into the same app twice on the same machine.
|
|
88
|
+
|
|
89
|
+
A visible browser opens; you do whatever the app asks. **Nothing to confirm afterwards** —
|
|
90
|
+
the window is watched, and the session is saved the moment it actually opens the app.
|
|
86
91
|
|
|
87
92
|
```console
|
|
88
93
|
$ ia-qa-discover login
|
|
@@ -92,16 +97,24 @@ $ ia-qa-discover login
|
|
|
92
97
|
Log in there however your app asks — SSO, MFA, a consent screen, all of it.
|
|
93
98
|
Nothing is typed for you, and no credential is read or stored by this tool.
|
|
94
99
|
|
|
95
|
-
|
|
100
|
+
Once the session actually opens the app, it is saved to:
|
|
96
101
|
.ia-qa-discovery/session.json
|
|
97
102
|
That file holds live session cookies: anyone who has it is logged in as you.
|
|
98
103
|
|
|
99
104
|
Open the browser now? [Y/n]
|
|
100
|
-
|
|
105
|
+
👀 Log in in the browser window. I am watching it — when the session actually opens
|
|
106
|
+
the app, I save it and carry on by myself. Nothing to come back and confirm here.
|
|
101
107
|
|
|
102
|
-
✅ Session saved — 7 cookies, 1 origin with local storage.
|
|
108
|
+
✅ Session saved and checked — 7 cookies, 1 origin with local storage.
|
|
109
|
+
Reopened https://app.example.com/dashboard with it in a clean browser: no login wall.
|
|
103
110
|
```
|
|
104
111
|
|
|
112
|
+
What "checked" means here is the same thing it means in `@ia-qa/self-healing`, because it is
|
|
113
|
+
the same code: the session is replayed in a clean browser and only written once it reaches
|
|
114
|
+
somewhere the logged-out one could not. An app that keeps its token in IndexedDB leaves
|
|
115
|
+
nothing a session file can hold — that used to print a green tick over an empty file written
|
|
116
|
+
on top of one that worked.
|
|
117
|
+
|
|
105
118
|
**3. Scan again — and hit the *second* way a page count lies.** The app navigates with React Router's `useNavigate()`, so there is not one `<a href>` to follow:
|
|
106
119
|
|
|
107
120
|
```console
|
|
@@ -241,7 +254,9 @@ Opens a **visible** browser, you log in by hand, and the session is saved for `s
|
|
|
241
254
|
|
|
242
255
|
This verb models nothing on purpose. A declarative `auth` block describes *one shape of login* — a username field, a password field, a submit button — and every app whose login is not that shape is out of reach: federated SSO, MFA, a consent screen, a magic link, a device check. Since you perform the login yourself, all of them work.
|
|
243
256
|
|
|
244
|
-
It refuses under CI and without a TTY: it waits for a person
|
|
257
|
+
It refuses under CI and without a TTY: it waits for a person at a browser, so a pipeline that runs it just hangs. **An agent cannot run this** — it must ask you to. For automation, point `--session` at a `storageState` your own setup already writes.
|
|
258
|
+
|
|
259
|
+
And often you do not need it at all: a session saved by `ia-qa-heal login` is picked up when this project has none of its own, announced on the scan (`sessionSource: "healing"`) and never written into your config. Nobody logs into the same app twice on the same machine.
|
|
245
260
|
|
|
246
261
|
The file it produces holds live cookies — whoever has it is logged in as you. The path is announced before the browser opens, `.ia-qa-discovery/.gitignore` is written on the way out, and nothing here uploads it.
|
|
247
262
|
|
|
@@ -263,6 +278,8 @@ It also reports **depth**: how many of each visited page's contracted elements y
|
|
|
263
278
|
|
|
264
279
|
**It needs a suite that was watched running.** That means `@ia-qa/self-healing` installed, `ia-qa-heal map`, and one `ia-qa-heal run`. Without it you get a refusal that names the command, not a number: a contract means somebody configured a page, and only a watched run means a test went there. "No measurement" and "zero coverage" are different sentences, and only one of them would be true.
|
|
265
280
|
|
|
281
|
+
**It joins two moments, and says which one is stale.** The map compares a suite run against a scan, and those happen at different times — so both dates are printed, and when they fall on different days the consequence is spelled out. The two errors run opposite ways: a suite run older than the scan makes "not tested" include *did not exist yet*, which is no gap in your suite at all; a scan older than the run means your tests may already visit pages nobody scanned, so the gap is wider on paper than in reality. Stating the gap without the stale half is how a number gets quoted in a meeting with none of its caveats.
|
|
282
|
+
|
|
266
283
|
**No percentage, ever.** A `34%` reads as code coverage — a ratio over a denominator a compiler guarantees. Here the denominator is uncertain by construction: a login wall, an app that navigates without `<a href>`, the page cap, states nothing opened. Counts and page names only, always beside what the scan could not see.
|
|
267
284
|
|
|
268
285
|
Writes `.ia-qa-discovery/coverage-map.json` (committable, diffable) and refreshes `_overview.md`. `--report [file.html] [--open]` for the branded dossier, `--json` for the map on stdout.
|
|
@@ -291,6 +308,8 @@ That loop is not a claim: it is executed on every commit, on this verb's own out
|
|
|
291
308
|
|
|
292
309
|
Left out for the same reason: a field with no test id, id or name. Its only selector is positional, and it addresses a different element the moment a field is inserted above it — untestable by anyone, not only by this tool. Each omission is named at the top of the file it was omitted from, because a silent gap reads as a finished test.
|
|
293
310
|
|
|
311
|
+
**A page it did not actually capture is left out too.** If the scan was shown a login form, or the app answered 404, then the capture is of *that* — and a spec written from it asserts a login or an error page under a feature's name, in a file that lands in your suite and gets run. It stays green for exactly as long as the app stays broken. The sibling package already refuses the same thing from the other side: `map` will not write a contract named `dashboard` that describes a login form. So those pages are held out of the default selection, **counted and named** with the reason, and the remedy offered (a session gets the scan past a wall). Naming a page generates for it anyway — the rule shapes a default, it does not overrule you — and `--include-login-walls` / `--include-error-pages` do it in bulk.
|
|
312
|
+
|
|
294
313
|
**The assertions are yours.** An application declares what it *accepts* — required, type, min, max — and never what it *promises*. "A refused card shows the right message" lives in someone's head, so the navigation and the actions are generated and what the app should *do* is a TODO with the question written out.
|
|
295
314
|
|
|
296
315
|
Files land in `.ia-qa-discovery/generated/` and nothing is added to your suite. An existing file is never replaced without `--force`. If the output directory is outside healing's `testPaths`, the verb says so and names both remedies — out of reach means never repaired, which would quietly make the whole promise false.
|
package/TUTORIAL.md
CHANGED
|
@@ -136,16 +136,17 @@ the terminal has, with the same guarantees.
|
|
|
136
136
|
|
|
137
137
|
### Step 4.3 — The one thing your agent cannot do
|
|
138
138
|
|
|
139
|
-
**It cannot log you in.** `login` opens a visible browser and waits for a human
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
*you* to run this, in your own terminal:
|
|
139
|
+
**It cannot log you in.** `login` opens a visible browser and waits for a human to log in.
|
|
140
|
+
That is not something an agent can perform, so it is deliberately not exposed as a tool. When
|
|
141
|
+
the scan reports a login wall, the agent will ask *you* to run this, in your own terminal:
|
|
143
142
|
|
|
144
143
|
```bash
|
|
145
144
|
npx -p @ia-qa/qa-discovery ia-qa-discover login
|
|
146
145
|
```
|
|
147
146
|
|
|
148
|
-
Then ask it to scan again.
|
|
147
|
+
Then ask it to scan again. **You may not need to at all:** if you already logged into this app
|
|
148
|
+
with `ia-qa-heal login`, the scan picks that session up on its own and says so — nobody logs
|
|
149
|
+
into the same app twice on the same machine.
|
|
149
150
|
|
|
150
151
|
---
|
|
151
152
|
|
|
@@ -195,6 +196,17 @@ Found 3 page(s). Capturing…
|
|
|
195
196
|
|
|
196
197
|
### Step 5.3 — Behind a login
|
|
197
198
|
|
|
199
|
+
**First, check whether you already are.** If you logged into this app with `ia-qa-heal login`
|
|
200
|
+
— directly, or because `ia-qa-pal tour` opened the browser for you — that session is picked up
|
|
201
|
+
automatically when this project has none of its own, and `scan` says so:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
🔓 Scanned with the session `ia-qa-heal login` saved (.ia-qa/session.json).
|
|
205
|
+
No second login needed — it was picked up because this project has no session of its own.
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Otherwise:
|
|
209
|
+
|
|
198
210
|
```bash
|
|
199
211
|
npx ia-qa-discover login
|
|
200
212
|
```
|
|
@@ -203,6 +215,11 @@ A visible browser opens. You log in **yourself** — SSO, MFA, a consent screen,
|
|
|
203
215
|
device check: all of them work, because the tool models none of them. Nothing is typed for you
|
|
204
216
|
and no credential is read or stored.
|
|
205
217
|
|
|
218
|
+
**There is nothing to confirm afterwards.** The window is watched, and the session is saved the
|
|
219
|
+
moment it actually opens the app — checked by replaying it in a clean browser, not by asking
|
|
220
|
+
you. An app that keeps its token in IndexedDB leaves nothing a session file can hold, and that
|
|
221
|
+
is reported instead of being written over the session you already had.
|
|
222
|
+
|
|
206
223
|
What is saved is the browser session, in `.ia-qa-discovery/session.json`. **That file holds live
|
|
207
224
|
cookies: whoever has it is logged in as you.** The tool says so before opening the browser and
|
|
208
225
|
writes a `.gitignore` next to it so a commit cannot carry it away.
|
|
@@ -276,7 +293,8 @@ before it was caught, and each is now stated out loud.
|
|
|
276
293
|
|
|
277
294
|
**1. The login wall.** Pages still showing a login form were captured — you measured the wall,
|
|
278
295
|
not the app. Worse: an app whose catch-all route renders the login page answers HTTP 200 at
|
|
279
|
-
*every* URL, so the count looks like a success. →
|
|
296
|
+
*every* URL, so the count looks like a success. → scan again if you have already logged in with
|
|
297
|
+
`ia-qa-heal login` (that session is picked up on its own); otherwise run `login`.
|
|
280
298
|
|
|
281
299
|
**2. No `<a href>` to follow.** Discovery follows links. An app navigating with React Router's
|
|
282
300
|
`navigate()` or a button's `onClick` exposes none, so an 11-route app reports "1 of 1 found".
|
|
@@ -519,11 +537,13 @@ npx ia-qa-discover-ai plan --report --open # the branded dossier, in a browser
|
|
|
519
537
|
**"Found 1 page" on an app I know has twenty.** Section 7, case 2 — the app navigates without
|
|
520
538
|
links. Declare the routes in `config.json` → `pages`.
|
|
521
539
|
|
|
522
|
-
**Everything is the login page.** Section 7, case 1.
|
|
540
|
+
**Everything is the login page.** Section 7, case 1. If you already logged in with
|
|
541
|
+
`ia-qa-heal login`, just scan again — that session is picked up automatically. Otherwise run
|
|
542
|
+
`login`, then scan again.
|
|
523
543
|
|
|
524
544
|
**`login` says it refuses.** It refuses without a terminal and under CI, because it waits for a
|
|
525
|
-
person
|
|
526
|
-
`storageState` your own setup writes.
|
|
545
|
+
person at a browser. That is also why an AI agent cannot run it. For a pipeline, point
|
|
546
|
+
`--session` at a `storageState` your own setup writes.
|
|
527
547
|
|
|
528
548
|
**"Nothing to show yet" from `coverage`.** Your suite has never been watched running. Run
|
|
529
549
|
`npx ia-qa-heal run` or `npx -p @ia-qa/pal ia-qa-pal tour --suite`. This is not zero coverage — it
|
package/dist/capture/page.d.ts
CHANGED
|
@@ -68,6 +68,16 @@ export interface CapturedForm {
|
|
|
68
68
|
fields: FormField[];
|
|
69
69
|
}
|
|
70
70
|
export declare const PAGE_CAPTURE_SCHEMA = "qa-discovery-page@1";
|
|
71
|
+
/**
|
|
72
|
+
* Does this capture hold a password field — in a `<form>` or loose?
|
|
73
|
+
*
|
|
74
|
+
* Lives beside the type rather than in whichever consumer wanted it first, because two
|
|
75
|
+
* readers now depend on answering it the same way: `loginWallPages` (is this scan looking at
|
|
76
|
+
* a wall instead of the app?) and `generate` (would this spec assert a login form under
|
|
77
|
+
* another page's name?). Both halves are load-bearing — a React login that submits in JS
|
|
78
|
+
* often has no `<form>` at all, so reading `forms` alone misses exactly the wall this is for.
|
|
79
|
+
*/
|
|
80
|
+
export declare function hasPasswordField(page: Pick<PageCapture, 'forms' | 'looseFields'>): boolean;
|
|
71
81
|
export interface PageCapture {
|
|
72
82
|
schema: typeof PAGE_CAPTURE_SCHEMA;
|
|
73
83
|
page: string;
|
package/dist/capture/page.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PAGE_CAPTURE_SCHEMA = void 0;
|
|
4
|
+
exports.hasPasswordField = hasPasswordField;
|
|
4
5
|
exports.capturePage = capturePage;
|
|
5
6
|
const extractPage_1 = require("../browser/extractPage");
|
|
6
7
|
const network_1 = require("../network");
|
|
7
8
|
const explore_1 = require("../explore");
|
|
8
9
|
exports.PAGE_CAPTURE_SCHEMA = 'qa-discovery-page@1';
|
|
10
|
+
/**
|
|
11
|
+
* Does this capture hold a password field — in a `<form>` or loose?
|
|
12
|
+
*
|
|
13
|
+
* Lives beside the type rather than in whichever consumer wanted it first, because two
|
|
14
|
+
* readers now depend on answering it the same way: `loginWallPages` (is this scan looking at
|
|
15
|
+
* a wall instead of the app?) and `generate` (would this spec assert a login form under
|
|
16
|
+
* another page's name?). Both halves are load-bearing — a React login that submits in JS
|
|
17
|
+
* often has no `<form>` at all, so reading `forms` alone misses exactly the wall this is for.
|
|
18
|
+
*/
|
|
19
|
+
function hasPasswordField(page) {
|
|
20
|
+
return (page.forms.some((f) => f.fields.some((fl) => fl.type === 'password')) ||
|
|
21
|
+
page.looseFields.some((fl) => fl.type === 'password'));
|
|
22
|
+
}
|
|
9
23
|
/**
|
|
10
24
|
* Capture one page's structural surface: meta/headings/forms via a single
|
|
11
25
|
* `page.evaluate`, and — unless disabled — observed API calls via a passive
|
package/dist/capture/page.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/capture/page.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/capture/page.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/args.js
CHANGED
|
@@ -21,10 +21,10 @@ exports.KNOWN_FLAGS = {
|
|
|
21
21
|
'--report',
|
|
22
22
|
'--open',
|
|
23
23
|
],
|
|
24
|
-
login: ['--url', '--session'],
|
|
24
|
+
login: ['--url', '--session', '--wait'],
|
|
25
25
|
history: ['--json', '--limit'],
|
|
26
26
|
coverage: ['--json', '--report', '--open'],
|
|
27
|
-
generate: ['--json', '--out', '--force'],
|
|
27
|
+
generate: ['--json', '--out', '--force', '--include-login-walls', '--include-error-pages'],
|
|
28
28
|
};
|
|
29
29
|
function rejectUnknownFlags(command, args) {
|
|
30
30
|
const known = exports.KNOWN_FLAGS[command];
|
package/dist/cli/args.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":";;;AAyBA,gDAQC;AAjCD,sGAAsG;AACzF,QAAA,WAAW,GAAsC;IAC5D,KAAK,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC;IAC7D,IAAI,EAAE;QACJ,SAAS;QACT,OAAO;QACP,aAAa;QACb,eAAe;QACf,WAAW;QACX,cAAc;QACd,cAAc;QACd,QAAQ;QACR,eAAe;QACf,qBAAqB;QACrB,QAAQ;QACR,QAAQ;QACR,UAAU;QACV,QAAQ;KACT;IACD,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":";;;AAyBA,gDAQC;AAjCD,sGAAsG;AACzF,QAAA,WAAW,GAAsC;IAC5D,KAAK,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC;IAC7D,IAAI,EAAE;QACJ,SAAS;QACT,OAAO;QACP,aAAa;QACb,eAAe;QACf,WAAW;QACX,cAAc;QACd,cAAc;QACd,QAAQ;QACR,eAAe;QACf,qBAAqB;QACrB,QAAQ;QACR,QAAQ;QACR,UAAU;QACV,QAAQ;KACT;IACD,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC;IACvC,OAAO,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC9B,QAAQ,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC;IAC1C,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAE,uBAAuB,CAAC;CAC3F,CAAC;AAEF,SAAgB,kBAAkB,CAAC,OAAe,EAAE,IAAc;IAChE,MAAM,KAAK,GAAG,mBAAW,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO;IAChC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACjC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,SAAS;QAChC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,yBAAyB,OAAO,kDAAkD,CAAC,CAAC;IACxH,CAAC;AACH,CAAC"}
|
package/dist/cli/generate.js
CHANGED
|
@@ -82,6 +82,12 @@ async function runGenerate(args) {
|
|
|
82
82
|
const force = args.includes('--force');
|
|
83
83
|
const { value: outDir, rest } = takeValueFlag(args, '--out', generatedDir());
|
|
84
84
|
const named = rest.filter((a) => !a.startsWith('-'));
|
|
85
|
+
const allowed = new Set();
|
|
86
|
+
if (args.includes(generate_1.INCLUDE_LOGIN_WALLS))
|
|
87
|
+
allowed.add('login-wall');
|
|
88
|
+
if (args.includes(generate_1.INCLUDE_ERROR_PAGES))
|
|
89
|
+
allowed.add('error-page');
|
|
90
|
+
const held = [];
|
|
85
91
|
const surface = (0, coverage_1.loadSurface)((0, config_1.captureDir)());
|
|
86
92
|
if (!surface) {
|
|
87
93
|
return refuse(json, 'No capture to generate from.', ['Run `ia-qa-discover scan` first — a test cannot be written for a page nobody has looked at.']);
|
|
@@ -126,6 +132,26 @@ async function runGenerate(args) {
|
|
|
126
132
|
`Name a page to generate for it anyway: ia-qa-discover generate <page…>`,
|
|
127
133
|
]);
|
|
128
134
|
}
|
|
135
|
+
// A login wall and an error page are captures of something other than the page they are
|
|
136
|
+
// named after, and a spec written from one asserts that other thing under this page's
|
|
137
|
+
// name. Applied to the default selection only — a named page is an explicit request.
|
|
138
|
+
for (const name of targets) {
|
|
139
|
+
const capture = byName.get(name);
|
|
140
|
+
const verdict = capture ? (0, generate_1.unsuitableForGeneration)(capture) : null;
|
|
141
|
+
if (verdict && !allowed.has(verdict.reason))
|
|
142
|
+
held.push(verdict);
|
|
143
|
+
}
|
|
144
|
+
const heldNames = new Set(held.map((h) => h.page));
|
|
145
|
+
targets = targets.filter((t) => !heldNames.has(t));
|
|
146
|
+
if (targets.length === 0) {
|
|
147
|
+
// Never an empty run reported as a success: the whole gap was captures of a login or
|
|
148
|
+
// an error, which is a finding about the scan, not a clean bill of coverage.
|
|
149
|
+
return refuse(json, `Nothing to generate: all ${held.length} untested page(s) were captured as a login wall or an error page.`, [
|
|
150
|
+
...held.map((h) => `· ${h.page} — ${h.why}`),
|
|
151
|
+
`A session gets the scan past a wall: ia-qa-discover scan --session <storageState.json>`,
|
|
152
|
+
`Or generate for one anyway by naming it: ia-qa-discover generate <page…>`,
|
|
153
|
+
]);
|
|
154
|
+
}
|
|
129
155
|
}
|
|
130
156
|
const mappingPath = path.join((0, config_1.baseDir)(), coverage_1.HEALING_DIR, 'mapping');
|
|
131
157
|
const specs = targets.map((name) => {
|
|
@@ -150,7 +176,7 @@ async function runGenerate(args) {
|
|
|
150
176
|
});
|
|
151
177
|
}
|
|
152
178
|
if (json) {
|
|
153
|
-
console.log(JSON.stringify({ written, kept, specs: specs.map(({ code, ...rest }) => rest) }, null, 2));
|
|
179
|
+
console.log(JSON.stringify({ written, kept, held, specs: specs.map(({ code, ...rest }) => rest) }, null, 2));
|
|
154
180
|
return;
|
|
155
181
|
}
|
|
156
182
|
console.log(`\n✍️ Generated ${written.length} spec${written.length === 1 ? '' : 's'} → ${path.relative(process.cwd(), outDir) || outDir}`);
|
|
@@ -163,6 +189,16 @@ async function runGenerate(args) {
|
|
|
163
189
|
for (const k of kept)
|
|
164
190
|
console.log(` · ${k}`);
|
|
165
191
|
}
|
|
192
|
+
// Counted and named. A page held out without being reported is a page nobody remembers to
|
|
193
|
+
// come back to, and the reader would have no way to tell it from one that was covered.
|
|
194
|
+
if (held.length > 0) {
|
|
195
|
+
console.log(`\n Not generated — ${held.length} page${held.length === 1 ? '' : 's'} the scan did not actually capture:`);
|
|
196
|
+
for (const h of held)
|
|
197
|
+
console.log(` · ${h.page} — ${h.why}`);
|
|
198
|
+
const flags = [...new Set(held.map((h) => h.flag))].join(' ');
|
|
199
|
+
console.log(` Naming one generates for it anyway, or: ia-qa-discover generate ${flags}\n` +
|
|
200
|
+
` For a login wall the real remedy is a session: ia-qa-discover scan --session <storageState.json>`);
|
|
201
|
+
}
|
|
166
202
|
const totalSkipped = specs.reduce((n, s) => n + s.skipped.length, 0);
|
|
167
203
|
if (totalSkipped > 0) {
|
|
168
204
|
console.log(`\n ${totalSkipped} field(s) were not generated — each says why at the top of its file.\n` +
|
package/dist/cli/generate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
declare const HELP = "ia-qa-discover \u2014 deterministic surface reconnaissance for a web app\n\nF1 of QA Discovery: crawl an app's same-origin pages and capture what each one\nis structurally about \u2014 title, headings, forms, and observed API calls. No\nLLM, no verdict: this is recon, not a gate. Runs entirely on your machine;\nnothing is uploaded anywhere.\n\n[FOR AI AGENTS] You are driving this for a human. Run `scan` to capture the\napp's surface, then read .ia-qa-discovery/capture/surface.json (the index) and\nthe per-page files it points at \u2014 that is the evidence for anything you\nreport about this app. Never assert a page's purpose or risk from the URL\nalone; ground it in the captured meta/headings/forms/apiCalls. Never read a\npage count as coverage: if scan warns that pages still show a login form, you\nmeasured the wall, not the app. You CANNOT run `login` \u2014 it waits for a human\nat a browser; ask them to run it, then scan again.\n`coverage` answers \"what does their suite NOT test\" \u2014 but only from a suite that was\nwatched running (one `ia-qa-heal run`, or one `ia-qa-pal tour --suite`). If it says there is no\nmeasurement, report that, never \"the suite covers nothing\": a contract means someone\nconfigured a page, only a watched run means a test went there.\n\nUsage:\n ia-qa-discover login Open a visible browser, log in by hand, keep the\n session (.ia-qa-discovery/session.json) for scan\n to reuse. The general answer to a login wall: it\n models nothing, so SSO, MFA, a consent screen or\n a magic link all work \u2014 you do them.\n Needs a terminal, refuses under CI. The file holds\n live cookies: gitignored, stays on this machine.\n --url <path> page to open (default: your baseUrl)\n --session <f> where to write it\n Already have a storageState (a Playwright globalSetup\n writes one)? Skip this verb: point scan at it with\n --session <file> or \"session\" in config.json.\n ia-qa-discover scan [url] Crawl same-origin pages from <url> (or the saved\n baseUrl) and capture each page's structure.\n Writes .ia-qa-discovery/capture/, diffs against\n the previous run, appends history.jsonl.\n --depth <n> crawl link-depth (default 2)\n --max <n> page cap (default 60)\n --deep also open menus, tabs and dialogs one level\n down and capture the fields they reveal. Every\n non-GET request is blocked for the duration,\n so a click cannot mutate anything server-side.\n --deep-budget <n> max controls clicked per page (default 60)\n --no-sitemap do not read sitemap.xml / robots.txt\n --no-reveal do not open menus/dropdowns for hidden links\n --strict-host treat www./apex as different hosts\n --session <file> reuse an existing storageState (login) file\n --no-network skip API/network-call capture this run\n --network-threshold <n> shared-call promotion threshold 0-1 (default 0.6)\n --save persist this baseUrl to config.json\n --json machine-readable summary on stdout\n --report [file.html] branded ia-qa.com HTML dossier of the\n app (default ia-qa-discover-report.html)\n --open open that report in the browser\n ia-qa-discover coverage What your test suite does NOT test. Compares the\n pages this scan found against the pages your suite\n was OBSERVED visiting, ranks the gap by what each\n page takes as input, and writes coverage-map.json.\n Reads local files only \u2014 no browser, no network.\n Needs one watched run of your suite \u2014\n \"ia-qa-heal run\" or \"ia-qa-pal tour --suite\":\n without a watched run there is no measurement, and\n it says so instead of showing a number.\n Declare pages you deliberately do not test in\n \"outOfScope\" in config.json \u2014 they stay counted\n and named, never silently dropped.\n --json machine-readable map on stdout\n --report [file.html] branded HTML dossier with the gap\n (default ia-qa-discover-coverage.html)\n --open open that report in the browser\n ia-qa-discover generate [page\u2026] A starting Playwright suite for the pages nothing\n tests \u2014 one file per page, into its own directory.\n Every locator names an element the healing contract\n holds, so the file is REPAIRED when the app moves\n instead of going red. A field with no test id, id or\n name is left out and says so: its selector would be\n positional, which nobody can test reliably.\n Proposals \u2014 nothing is added to your suite, and the\n assertions stay yours (the app declares what it\n accepts, never what it promises).\n With no page, it generates for the coverage gap.\n --out <dir> where to write (default\n .ia-qa-discovery/generated/)\n --force replace files already there\n --json machine-readable summary on stdout\n ia-qa-discover skill This CLI's agent instructions: the verb for each\n question, what every refusal means, and what an\n agent must never do. Read them before driving\n anything else here.\n --print write them to stdout and stop\n --install write .claude/skills/ia-qa-discover/\n --user into ~/ instead of this project\n --dir <d> into another project root\n --force overwrite an edited copy\n ia-qa-discover history Recorded scan runs \u2014 pages/forms/API-surface trend.\n --json --limit <n> (default 500)\n ia-qa-discover version Print the installed version (also --version, -v)\n ia-qa-discover help Show this help\n\nGlobal:\n --config <dir> Resolve .ia-qa-discovery/ under <dir> instead of the\n current directory. Also IAQA_DISCOVERY_CONFIG_DIR=<dir>.\n";
|
|
2
|
+
declare const HELP = "ia-qa-discover \u2014 deterministic surface reconnaissance for a web app\n\nF1 of QA Discovery: crawl an app's same-origin pages and capture what each one\nis structurally about \u2014 title, headings, forms, and observed API calls. No\nLLM, no verdict: this is recon, not a gate. Runs entirely on your machine;\nnothing is uploaded anywhere.\n\n[FOR AI AGENTS] You are driving this for a human. Run `scan` to capture the\napp's surface, then read .ia-qa-discovery/capture/surface.json (the index) and\nthe per-page files it points at \u2014 that is the evidence for anything you\nreport about this app. Never assert a page's purpose or risk from the URL\nalone; ground it in the captured meta/headings/forms/apiCalls. Never read a\npage count as coverage: if scan warns that pages still show a login form, you\nmeasured the wall, not the app. You CANNOT run `login` \u2014 it waits for a human\nat a browser; ask them to run it, then scan again.\n`coverage` answers \"what does their suite NOT test\" \u2014 but only from a suite that was\nwatched running (one `ia-qa-heal run`, or one `ia-qa-pal tour --suite`). If it says there is no\nmeasurement, report that, never \"the suite covers nothing\": a contract means someone\nconfigured a page, only a watched run means a test went there.\n\nUsage:\n ia-qa-discover login Open a visible browser, log in by hand, keep the\n session (.ia-qa-discovery/session.json) for scan\n to reuse. The general answer to a login wall: it\n models nothing, so SSO, MFA, a consent screen or\n a magic link all work \u2014 you do them.\n Needs a terminal, refuses under CI. The file holds\n live cookies: gitignored, stays on this machine.\n Nothing to confirm afterwards: the window is\n watched and the session is saved the moment it\n actually opens the app. Already logged in with\n ia-qa-heal login? You do not need this at all \u2014\n scan picks that session up and says so.\n --wait <s> how long to watch (0 = press Enter)\n --url <path> page to open (default: your baseUrl)\n --session <f> where to write it\n Already have a storageState (a Playwright globalSetup\n writes one)? Skip this verb: point scan at it with\n --session <file> or \"session\" in config.json.\n ia-qa-discover scan [url] Crawl same-origin pages from <url> (or the saved\n baseUrl) and capture each page's structure.\n Writes .ia-qa-discovery/capture/, diffs against\n the previous run, appends history.jsonl.\n --depth <n> crawl link-depth (default 2)\n --max <n> page cap (default 60)\n --deep also open menus, tabs and dialogs one level\n down and capture the fields they reveal. Every\n non-GET request is blocked for the duration,\n so a click cannot mutate anything server-side.\n --deep-budget <n> max controls clicked per page (default 60)\n --no-sitemap do not read sitemap.xml / robots.txt\n --no-reveal do not open menus/dropdowns for hidden links\n --strict-host treat www./apex as different hosts\n --session <file> reuse an existing storageState (login) file\n --no-network skip API/network-call capture this run\n --network-threshold <n> shared-call promotion threshold 0-1 (default 0.6)\n --save persist this baseUrl to config.json\n --json machine-readable summary on stdout\n --report [file.html] branded ia-qa.com HTML dossier of the\n app (default ia-qa-discover-report.html)\n --open open that report in the browser\n ia-qa-discover coverage What your test suite does NOT test. Compares the\n pages this scan found against the pages your suite\n was OBSERVED visiting, ranks the gap by what each\n page takes as input, and writes coverage-map.json.\n Reads local files only \u2014 no browser, no network.\n Needs one watched run of your suite \u2014\n \"ia-qa-heal run\" or \"ia-qa-pal tour --suite\":\n without a watched run there is no measurement, and\n it says so instead of showing a number.\n Declare pages you deliberately do not test in\n \"outOfScope\" in config.json \u2014 they stay counted\n and named, never silently dropped.\n --json machine-readable map on stdout\n --report [file.html] branded HTML dossier with the gap\n (default ia-qa-discover-coverage.html)\n --open open that report in the browser\n ia-qa-discover generate [page\u2026] A starting Playwright suite for the pages nothing\n tests \u2014 one file per page, into its own directory.\n Every locator names an element the healing contract\n holds, so the file is REPAIRED when the app moves\n instead of going red. A field with no test id, id or\n name is left out and says so: its selector would be\n positional, which nobody can test reliably.\n Proposals \u2014 nothing is added to your suite, and the\n assertions stay yours (the app declares what it\n accepts, never what it promises).\n With no page, it generates for the coverage gap,\n minus the pages captured as a login wall or an\n error \u2014 those specs would assert a login form or\n a 404 under a feature's name. They are named, and\n naming one generates for it anyway.\n --out <dir> where to write (default\n .ia-qa-discovery/generated/)\n --force replace files already there\n --include-login-walls, --include-error-pages\n generate for those too\n --json machine-readable summary on stdout\n ia-qa-discover skill This CLI's agent instructions: the verb for each\n question, what every refusal means, and what an\n agent must never do. Read them before driving\n anything else here.\n --print write them to stdout and stop\n --install write .claude/skills/ia-qa-discover/\n --user into ~/ instead of this project\n --dir <d> into another project root\n --force overwrite an edited copy\n ia-qa-discover history Recorded scan runs \u2014 pages/forms/API-surface trend.\n --json --limit <n> (default 500)\n ia-qa-discover version Print the installed version (also --version, -v)\n ia-qa-discover help Show this help\n\nGlobal:\n --config <dir> Resolve .ia-qa-discovery/ under <dir> instead of the\n current directory. Also IAQA_DISCOVERY_CONFIG_DIR=<dir>.\n";
|
|
3
3
|
declare function verbHelp(command: string | undefined): string | null;
|
|
4
4
|
declare function main(): Promise<void>;
|
|
5
5
|
export { HELP, verbHelp, main };
|
package/dist/cli/index.js
CHANGED
|
@@ -42,6 +42,12 @@ Usage:
|
|
|
42
42
|
a magic link all work — you do them.
|
|
43
43
|
Needs a terminal, refuses under CI. The file holds
|
|
44
44
|
live cookies: gitignored, stays on this machine.
|
|
45
|
+
Nothing to confirm afterwards: the window is
|
|
46
|
+
watched and the session is saved the moment it
|
|
47
|
+
actually opens the app. Already logged in with
|
|
48
|
+
ia-qa-heal login? You do not need this at all —
|
|
49
|
+
scan picks that session up and says so.
|
|
50
|
+
--wait <s> how long to watch (0 = press Enter)
|
|
45
51
|
--url <path> page to open (default: your baseUrl)
|
|
46
52
|
--session <f> where to write it
|
|
47
53
|
Already have a storageState (a Playwright globalSetup
|
|
@@ -95,10 +101,16 @@ Usage:
|
|
|
95
101
|
Proposals — nothing is added to your suite, and the
|
|
96
102
|
assertions stay yours (the app declares what it
|
|
97
103
|
accepts, never what it promises).
|
|
98
|
-
With no page, it generates for the coverage gap
|
|
104
|
+
With no page, it generates for the coverage gap,
|
|
105
|
+
minus the pages captured as a login wall or an
|
|
106
|
+
error — those specs would assert a login form or
|
|
107
|
+
a 404 under a feature's name. They are named, and
|
|
108
|
+
naming one generates for it anyway.
|
|
99
109
|
--out <dir> where to write (default
|
|
100
110
|
.ia-qa-discovery/generated/)
|
|
101
111
|
--force replace files already there
|
|
112
|
+
--include-login-walls, --include-error-pages
|
|
113
|
+
generate for those too
|
|
102
114
|
--json machine-readable summary on stdout
|
|
103
115
|
ia-qa-discover skill This CLI's agent instructions: the verb for each
|
|
104
116
|
question, what every refusal means, and what an
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;;AA8Oe,4BAAQ;AAAE,oBAAI;AA7O7B,sCAAuC;AACvC,iCAAyD;AACzD,iCAAiC;AACjC,mCAAmC;AACnC,uCAAuC;AACvC,yCAAyC;AACzC,yCAAyC;AACzC,mCAAmC;AAEnC,qEAAqE;AACrE,MAAM,OAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC,OAAiB,CAAC;AAEhE,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmHZ,CAAC;AA8GO,oBAAI;AA5Gb,SAAS,gBAAgB,CAAC,IAAc;IACtC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,GAAuB,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,UAAU,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;YAClF,CAAC;YACD,GAAG,GAAG,IAAI,CAAC;YACX,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9B,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAClC,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACf,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AACvB,CAAC;AAED,SAAS,QAAQ,CAAC,OAA2B;IAC3C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACrD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAC3B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,oBAAoB,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,oBAAoB,OAAO,EAAE,CAC3F,CAAC;IACF,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;YAClC,MAAM;IACb,CAAC;IACD,MAAM,KAAK,GAAG,kBAAW,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;IAChF,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,oCAAoC,CAAC;AACxE,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACxE,IAAA,mBAAU,EAAC,SAAS,CAAC,CAAC;IACxB,CAAC;IAED,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,SAAS;QAAE,IAAA,yBAAkB,EAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAE7D,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,MAAM,IAAA,cAAO,EAAC,IAAI,CAAC,CAAC;YACpB,MAAM;QACR,KAAK,OAAO;YACV,MAAM,IAAA,gBAAQ,EAAC,IAAI,CAAC,CAAC;YACrB,MAAM;QACR,KAAK,UAAU;YACb,MAAM,IAAA,sBAAW,EAAC,IAAI,CAAC,CAAC;YACxB,MAAM;QACR,KAAK,UAAU;YACb,MAAM,IAAA,sBAAW,EAAC,IAAI,CAAC,CAAC;YACxB,MAAM;QACR,KAAK,SAAS;YACZ,MAAM,IAAA,oBAAU,EAAC,IAAI,CAAC,CAAC;YACvB,MAAM;QACR,KAAK,OAAO;YACV,MAAM,IAAA,gBAAQ,EAAC,IAAI,CAAC,CAAC;YACrB,MAAM;QACR,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACrB,MAAM;QACR,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI,CAAC;QACV,KAAK,SAAS;YACZ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,SAAS,IAAI,EAAE,CAAC,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;IAAE,GAAG,EAAE,CAAC;AAEnC,SAAS,GAAG;IACV,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QAC5B,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/cli/login.js
CHANGED
|
@@ -36,7 +36,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.runLogin = runLogin;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
-
const readline = __importStar(require("readline/promises"));
|
|
40
39
|
const self_healing_1 = require("@ia-qa/self-healing");
|
|
41
40
|
const config_1 = require("../config");
|
|
42
41
|
/**
|
|
@@ -107,54 +106,36 @@ async function runLogin(args) {
|
|
|
107
106
|
return;
|
|
108
107
|
}
|
|
109
108
|
const file = (0, config_1.sessionTarget)(config, explicit).file;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
120
|
-
try {
|
|
121
|
-
const go = (await rl.question('Open the browser now? [Y/n] ')).trim().toLowerCase();
|
|
122
|
-
if (go === 'n' || go === 'no') {
|
|
123
|
-
console.log('Nothing opened, nothing written.');
|
|
124
|
-
process.exitCode = 1;
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
const { browser, using } = await (0, self_healing_1.launchBrowser)({ headed: true });
|
|
128
|
-
console.log(`🌐 Using ${using} (visible window)`);
|
|
129
|
-
try {
|
|
130
|
-
const locale = config?.locale || process.env.IAQA_LOCALE;
|
|
131
|
-
const context = await browser.newContext(locale ? { locale } : {});
|
|
132
|
-
const page = await context.newPage();
|
|
133
|
-
await page.goto(target, { waitUntil: 'domcontentloaded', timeout: 60000 });
|
|
134
|
-
await rl.question('Logged in? (leave the browser open — press Enter here when the app is showing) ');
|
|
135
|
-
// Saved as-is, on the human's word. Nothing here can tell "logged in" from
|
|
136
|
-
// "still on step 2 of the SSO" for an arbitrary app, and claiming otherwise
|
|
137
|
-
// would be the false green this package exists to avoid. `scan` finds out
|
|
138
|
-
// for real — it warns when the pages it captured still show a login form.
|
|
139
|
-
const landed = page.url();
|
|
140
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
141
|
-
const state = await context.storageState({ path: file });
|
|
142
|
-
writeSessionGitignore();
|
|
143
|
-
const origins = state.origins?.length || 0;
|
|
144
|
-
console.log(`\n✅ Session saved — ${state.cookies.length} cookies, ${origins} ${origins === 1 ? 'origin' : 'origins'} with local storage.`);
|
|
145
|
-
console.log(` ${file}`);
|
|
146
|
-
console.log(` Browser was on ${landed} when it was taken.`);
|
|
147
|
-
console.log(` \`ia-qa-discover scan\` will reuse it automatically. A saved session is a`);
|
|
148
|
-
console.log(` local artefact with a shelf life — when it expires, scan sees the login`);
|
|
149
|
-
console.log(` wall again and says to re-run this.`);
|
|
150
|
-
}
|
|
151
|
-
finally {
|
|
152
|
-
await browser.close();
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
finally {
|
|
156
|
-
rl.close();
|
|
109
|
+
const locale = config?.locale || process.env.IAQA_LOCALE;
|
|
110
|
+
// Same flag and same default as the sibling: the watch replaces "press Enter", and 0
|
|
111
|
+
// restores the manual step for an app whose login cannot be observed from the outside.
|
|
112
|
+
const waitIdx = args.indexOf('--wait');
|
|
113
|
+
const waitSeconds = waitIdx !== -1 ? Number(args[waitIdx + 1]) : 600;
|
|
114
|
+
if (waitIdx !== -1 && (!Number.isFinite(waitSeconds) || waitSeconds < 0)) {
|
|
115
|
+
console.error('❌ --wait needs a number of seconds (0 turns the watch off).');
|
|
116
|
+
process.exitCode = 2;
|
|
117
|
+
return;
|
|
157
118
|
}
|
|
119
|
+
// Everything from the announcement to the write is `performLogin`, imported from
|
|
120
|
+
// `@ia-qa/self-healing`. What stood here was a hand-written twin of that verb as it was
|
|
121
|
+
// BEFORE both of its corrections: it asked "Logged in? press Enter", then called
|
|
122
|
+
// `storageState({ path })` — which writes before anything is checked — and printed
|
|
123
|
+
// `✅ Session saved — N cookies`. So an app keeping its token in IndexedDB got a green
|
|
124
|
+
// tick over an empty file written on top of one that worked, which is the exact defect
|
|
125
|
+
// the sibling had already fixed and documented. A doctrine repaired in one copy only is
|
|
126
|
+
// not a doctrine, and "does this session open the app" is the same question here.
|
|
127
|
+
//
|
|
128
|
+
// What stays local is what is genuinely narrower: this package's paths, its URL rules,
|
|
129
|
+
// its own .gitignore and its own refusals above.
|
|
130
|
+
await (0, self_healing_1.performLogin)({
|
|
131
|
+
verb: `ia-qa-discover login`,
|
|
132
|
+
target,
|
|
133
|
+
file,
|
|
134
|
+
gitignore: `${config_1.CONFIG_DIR}/.gitignore`,
|
|
135
|
+
writeGitignore: writeSessionGitignore,
|
|
136
|
+
contextOptions: locale ? { locale } : {},
|
|
137
|
+
waitSeconds,
|
|
138
|
+
});
|
|
158
139
|
}
|
|
159
140
|
/**
|
|
160
141
|
* `.ia-qa-discovery/.gitignore`, scoped to the one file in there that is a
|
package/dist/cli/login.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/cli/login.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/cli/login.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/scan.js
CHANGED
|
@@ -202,7 +202,11 @@ async function runScan(args) {
|
|
|
202
202
|
`(${result.loginWall.join(', ')}).`);
|
|
203
203
|
console.log(` You are very likely looking at the login wall, not the app — a page count is not coverage.`);
|
|
204
204
|
console.log(result.session
|
|
205
|
-
?
|
|
205
|
+
? // Whoever wrote the session is who should refresh it: telling someone to run this
|
|
206
|
+
// package's `login` over a file the sibling owns leaves two sessions for the same
|
|
207
|
+
// app and refreshes the one that was not being used.
|
|
208
|
+
` The saved session (${result.session}) did not get past it: it may have expired.\n` +
|
|
209
|
+
` Refresh it: \`${result.sessionSource === 'healing' ? 'ia-qa-heal login' : 'ia-qa-discover login'}\`.`
|
|
206
210
|
: ` Run \`ia-qa-discover login\` to log in by hand once, then scan again.`);
|
|
207
211
|
}
|
|
208
212
|
else if (result.loginWall.length === 1 && !result.session) {
|
|
@@ -214,7 +218,14 @@ async function runScan(args) {
|
|
|
214
218
|
console.log(` Run \`ia-qa-discover login\` to log in by hand once, then scan again.`);
|
|
215
219
|
}
|
|
216
220
|
else if (result.session) {
|
|
217
|
-
|
|
221
|
+
// A borrowed session is named as borrowed. It was not asked for in this command, and a
|
|
222
|
+
// credential used without being asked for is one that has to be announced — the
|
|
223
|
+
// alternative is somebody reading an authenticated surface as the public one, or the
|
|
224
|
+
// reverse. Nothing leaves the machine either way; the announcement is about the reader.
|
|
225
|
+
console.log(result.sessionSource === 'healing'
|
|
226
|
+
? `\n🔓 Scanned with the session \`ia-qa-heal login\` saved (${result.session}).\n` +
|
|
227
|
+
` No second login needed — it was picked up because this project has no session of its own.`
|
|
228
|
+
: `\n🔓 Scanned with the saved session (${result.session}).`);
|
|
218
229
|
}
|
|
219
230
|
// A loaded page is one state of a page. Where the input surface hides behind
|
|
220
231
|
// clicks, the field count above is honest only if it says so.
|