form-tester 0.10.0 → 0.10.2
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/.github/copilot-instructions.md +76 -67
- package/form-tester.config.example.json +3 -1
- package/form-tester.js +20 -4
- package/package.json +1 -1
|
@@ -10,96 +10,105 @@ npm install -g form-tester
|
|
|
10
10
|
form-tester install
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
## Running
|
|
13
|
+
## Running a test
|
|
14
14
|
|
|
15
|
+
When the user gives you a form URL to test, execute ALL steps below in sequence WITHOUT stopping to ask. Do not ask "want me to continue?" — just do the entire flow.
|
|
16
|
+
|
|
17
|
+
### Step 1 — Start the test
|
|
15
18
|
```bash
|
|
16
|
-
# AI mode (default) — no prompts:
|
|
17
19
|
form-tester test <url> --auto
|
|
20
|
+
```
|
|
21
|
+
Or with options:
|
|
22
|
+
```bash
|
|
18
23
|
form-tester test <url> --auto --pnr 12345 --persona ung-mann --scenario "test validation"
|
|
19
|
-
|
|
20
|
-
# Human mode — user chooses persona and scenario:
|
|
21
|
-
form-tester test <url> --human # lists personas
|
|
22
|
-
form-tester test <url> --human --persona ung-mann --scenario "test X" # run with choices
|
|
23
|
-
|
|
24
|
-
# Full interactive CLI:
|
|
25
|
-
form-tester
|
|
26
24
|
```
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
2. Ask the user to pick a persona and scenario.
|
|
33
|
-
3. Re-run: `form-tester test <url> --human --persona <id> --scenario "<text>"` (use `""` for standard test).
|
|
34
|
-
Otherwise default to `--auto`.
|
|
35
|
-
|
|
36
|
-
## Commands
|
|
37
|
-
|
|
38
|
-
| Command | Description |
|
|
39
|
-
|---------|-------------|
|
|
40
|
-
| `/setup` | Initial setup |
|
|
41
|
-
| `/update` | Update Playwright CLI + skills |
|
|
42
|
-
| `/version` | Show version |
|
|
43
|
-
| `/people` | Rescan visible person list |
|
|
44
|
-
| `/test {url}` | Test a form URL |
|
|
45
|
-
| `/save {label}` | Save snapshot + screenshot |
|
|
46
|
-
| `/clear` | Clear session |
|
|
47
|
-
| `/quit` | Exit CLI |
|
|
48
|
-
|
|
49
|
-
## Playwright CLI (use via form-tester exec)
|
|
26
|
+
### Step 2 — Dismiss cookies
|
|
27
|
+
```bash
|
|
28
|
+
form-tester cookies
|
|
29
|
+
```
|
|
50
30
|
|
|
51
|
-
|
|
31
|
+
### Step 3 — Select person
|
|
32
|
+
```bash
|
|
33
|
+
form-tester select-person
|
|
34
|
+
```
|
|
35
|
+
To select a specific person: `form-tester select-person "Name"`
|
|
52
36
|
|
|
37
|
+
### Step 4 — Study the form
|
|
38
|
+
Take a snapshot and identify ALL sections and required fields:
|
|
53
39
|
```bash
|
|
54
|
-
form-tester exec open https://example.com
|
|
55
40
|
form-tester exec snapshot
|
|
56
|
-
form-tester exec fill e1 "value"
|
|
57
|
-
form-tester exec click e3
|
|
58
|
-
form-tester exec screenshot --filename=page.png --full-page
|
|
59
|
-
form-tester exec close # finalizes recording
|
|
60
41
|
```
|
|
42
|
+
Look for collapsed/accordion sections (buttons with arrow icons). Expand ALL of them by clicking their header buttons before filling anything.
|
|
61
43
|
|
|
62
|
-
|
|
44
|
+
### Step 5 — Fill the form
|
|
45
|
+
Use `form-tester exec` for ALL commands (this records them for replay):
|
|
63
46
|
```bash
|
|
64
|
-
form-tester
|
|
47
|
+
form-tester exec fill <ref> "value"
|
|
48
|
+
form-tester exec click <ref>
|
|
49
|
+
form-tester exec select <ref> "option text"
|
|
50
|
+
form-tester exec screenshot --filename "path.png" --full-page
|
|
65
51
|
```
|
|
66
52
|
|
|
67
|
-
|
|
53
|
+
For autosuggest/search fields: fill the text, wait for dropdown, then click the suggestion:
|
|
54
|
+
```bash
|
|
55
|
+
form-tester exec fill <ref> "search text"
|
|
56
|
+
form-tester exec snapshot # find the suggestion element
|
|
57
|
+
form-tester exec click <suggestion-ref>
|
|
58
|
+
```
|
|
68
59
|
|
|
69
|
-
|
|
60
|
+
### Step 6 — Submit
|
|
61
|
+
Take a screenshot, then click the submit button.
|
|
70
62
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
63
|
+
### Step 7 — Handle validation errors
|
|
64
|
+
IMPORTANT: If validation errors appear after submit, the form DID NOT SUBMIT. Run:
|
|
65
|
+
```bash
|
|
66
|
+
form-tester validate
|
|
67
|
+
```
|
|
68
|
+
This parses all validation errors, clicks each error link to scroll to the field, and shows what needs to be filled. Fix each field, then run `form-tester validate` again to confirm. Only then resubmit.
|
|
75
69
|
|
|
76
|
-
|
|
70
|
+
RULES:
|
|
71
|
+
- Maximum 3 submit attempts. After 3, STOP and write results.
|
|
72
|
+
- Do NOT re-fill fields that are already filled.
|
|
73
|
+
- Do NOT use JavaScript `dispatchEvent` or `element.evaluate()` to set values.
|
|
74
|
+
- Always use Playwright's `fill`, `click`, `select` commands.
|
|
77
75
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
- If an error modal appears on submit, open DevTools -> Network, retry once, and capture the Correlation ID header.
|
|
76
|
+
### Step 8 — Post-submit verification
|
|
77
|
+
After successful submission, read the modal text:
|
|
78
|
+
- If it mentions Dokumenter storage ("lagret i Dokumenter") → run document verification
|
|
79
|
+
- If it does NOT mention Dokumenter → skip, note in test_results.txt
|
|
83
80
|
|
|
84
|
-
|
|
81
|
+
### Step 9 — Document verification
|
|
82
|
+
```bash
|
|
83
|
+
form-tester documents
|
|
84
|
+
```
|
|
85
|
+
This handles everything: navigate to Dokumenter, find latest doc, detect PDF vs HTML, download or screenshot.
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
87
|
+
### Step 10 — Finalize
|
|
88
|
+
- Write test_results.txt with status, data used, and notes
|
|
89
|
+
- Close browser: `form-tester exec close`
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
## Issue logging
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
form-tester exec run-code "async page => { const link = page.locator('a[href*=\"/pdf/\"]').first(); const [download] = await Promise.all([ page.waitForEvent('download'), link.click() ]); await download.saveAs('$OUTPUT_DIR/document.pdf'); }"
|
|
97
|
-
```
|
|
98
|
-
Or if there's a "Last ned" button:
|
|
99
|
-
```
|
|
100
|
-
form-tester exec run-code "async page => { const [download] = await Promise.all([ page.waitForEvent('download'), page.getByRole('link', { name: 'Last ned' }).click() ]); await download.saveAs('$OUTPUT_DIR/document.pdf'); }"
|
|
93
|
+
When something unexpected happens, log it:
|
|
94
|
+
```bash
|
|
95
|
+
form-tester issue <category> "<description>"
|
|
101
96
|
```
|
|
97
|
+
Categories: `person-selection`, `navigation`, `form-fill`, `submission`, `documents`, `pdf-download`, `html-capture`, `screenshot`, `snapshot`, `validation`, `modal`, `timeout`, `other`
|
|
98
|
+
|
|
99
|
+
View recent issues: `form-tester issues`
|
|
100
|
+
|
|
101
|
+
## Important rules
|
|
102
|
+
|
|
103
|
+
- ALWAYS use `form-tester exec` instead of `playwright-cli` directly
|
|
104
|
+
- ALL screenshots MUST use `--full-page`
|
|
105
|
+
- Take a screenshot EVERY TIME the page changes
|
|
106
|
+
- Do NOT stop to ask the user between steps — execute the full flow
|
|
107
|
+
- Persona IDs: `ung-mann`, `gravid-kvinne`, `eldre-kvinne`, `kronisk-syk-mann`, `noen`
|
|
102
108
|
|
|
103
|
-
|
|
109
|
+
## Human mode
|
|
104
110
|
|
|
105
|
-
|
|
111
|
+
When user asks for `--human` mode:
|
|
112
|
+
1. Run `form-tester test <url> --human` to get persona list
|
|
113
|
+
2. Ask user to pick persona and scenario
|
|
114
|
+
3. Re-run: `form-tester test <url> --human --persona <id> --scenario "<text>"`
|
package/form-tester.js
CHANGED
|
@@ -7,7 +7,7 @@ const { spawn, execSync } = require("child_process");
|
|
|
7
7
|
const CONFIG_PATH = path.join(process.cwd(), "form-tester.config.json");
|
|
8
8
|
const OUTPUT_BASE = path.resolve(process.cwd(), "output");
|
|
9
9
|
const ISSUES_PATH = path.join(OUTPUT_BASE, "issues.jsonl");
|
|
10
|
-
const LOCAL_VERSION = "0.10.
|
|
10
|
+
const LOCAL_VERSION = "0.10.2";
|
|
11
11
|
const RECOMMENDED_PERSON = "Uromantisk Direktør";
|
|
12
12
|
|
|
13
13
|
// Recording — persisted to disk so `form-tester exec` can append across processes
|
|
@@ -300,6 +300,12 @@ async function handleSelectPerson(config, targetName) {
|
|
|
300
300
|
const v = "normal";
|
|
301
301
|
const log = (msg) => console.log(msg);
|
|
302
302
|
|
|
303
|
+
// Use config.person as default if no target specified
|
|
304
|
+
if (!targetName && config.person) {
|
|
305
|
+
targetName = config.person;
|
|
306
|
+
log(`Using configured person: ${targetName}`);
|
|
307
|
+
}
|
|
308
|
+
|
|
303
309
|
// Step 1: Try to find person list from current page snapshot
|
|
304
310
|
const tmpSnapshot = path.join(
|
|
305
311
|
config.lastRunDir || OUTPUT_BASE,
|
|
@@ -651,6 +657,8 @@ async function promptPersona(config) {
|
|
|
651
657
|
}
|
|
652
658
|
const DEFAULT_CONFIG = {
|
|
653
659
|
pnr: "",
|
|
660
|
+
person: "",
|
|
661
|
+
baseUrl: "",
|
|
654
662
|
dokumenterUrlTemplate: "/dokumenter?pnr={PNR}",
|
|
655
663
|
lastTestUrl: "",
|
|
656
664
|
lastRunDir: "",
|
|
@@ -673,11 +681,17 @@ function saveConfig(config) {
|
|
|
673
681
|
|
|
674
682
|
function resolveDokumenterUrl(config) {
|
|
675
683
|
if (!config.dokumenterUrlTemplate) return "";
|
|
676
|
-
|
|
684
|
+
let url = config.dokumenterUrlTemplate;
|
|
685
|
+
if (url.includes("{PNR}")) {
|
|
677
686
|
if (!config.pnr) return "";
|
|
678
|
-
|
|
687
|
+
url = url.replace("{PNR}", config.pnr);
|
|
688
|
+
}
|
|
689
|
+
// If the URL is a relative path, prepend the base URL
|
|
690
|
+
if (url.startsWith("/")) {
|
|
691
|
+
const base = config.baseUrl || (config.lastTestUrl ? (() => { try { return new URL(config.lastTestUrl).origin; } catch (e) { return ""; } })() : "");
|
|
692
|
+
if (base) url = `${base}${url}`;
|
|
679
693
|
}
|
|
680
|
-
return
|
|
694
|
+
return url;
|
|
681
695
|
}
|
|
682
696
|
|
|
683
697
|
function extractPnrFromUrl(url) {
|
|
@@ -1346,6 +1360,7 @@ async function handleTest(url, config) {
|
|
|
1346
1360
|
|
|
1347
1361
|
config.lastTestUrl = updated.url;
|
|
1348
1362
|
config.lastRunDir = outputDir;
|
|
1363
|
+
try { config.baseUrl = new URL(updated.url).origin; } catch (e) {}
|
|
1349
1364
|
saveConfig(config);
|
|
1350
1365
|
|
|
1351
1366
|
// Start recording and persist path to config for `exec`
|
|
@@ -1463,6 +1478,7 @@ async function handleTestAuto(url, config, flags) {
|
|
|
1463
1478
|
|
|
1464
1479
|
config.lastTestUrl = fullUrl;
|
|
1465
1480
|
config.lastRunDir = outputDir;
|
|
1481
|
+
try { config.baseUrl = new URL(fullUrl).origin; } catch (e) {}
|
|
1466
1482
|
saveConfig(config);
|
|
1467
1483
|
|
|
1468
1484
|
// Start recording and persist path to config for `exec`
|
package/package.json
CHANGED