form-tester 0.7.0 → 0.7.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.
|
@@ -10,17 +10,21 @@ Install skill files:
|
|
|
10
10
|
form-tester install
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
form-tester
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Non-interactive mode (best for AI agents):
|
|
13
|
+
Test modes:
|
|
19
14
|
```
|
|
15
|
+
# AI mode (default) — no prompts:
|
|
20
16
|
form-tester test <url> --auto
|
|
21
17
|
form-tester test <url> --auto --pnr 12345 --persona ung-mann
|
|
18
|
+
|
|
19
|
+
# Human mode — prompts for persona, scenario, person selection:
|
|
20
|
+
form-tester test <url> --human
|
|
21
|
+
|
|
22
|
+
# Full interactive CLI:
|
|
23
|
+
form-tester
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
When the user asks for human/interactive mode, use `--human`. Otherwise default to `--auto`.
|
|
27
|
+
|
|
24
28
|
Commands:
|
|
25
29
|
```
|
|
26
30
|
/setup
|
|
@@ -43,8 +47,9 @@ Notes:
|
|
|
43
47
|
- Use the next-step checklist printed by the CLI (cookies, person selection, validation fix, Dokumenter verification, save HTML/PDF).
|
|
44
48
|
- If the error modal appears on save or submit ("Det skjedde en feil under innsending av skjema. Prøv igjen senere."), open DevTools -> Network before retrying. Then try resubmitting once. If it persists, find the failed request and capture the Correlation ID header in test_results.txt.
|
|
45
49
|
- Use `--help` or `-h` to print the command list without starting the prompt.
|
|
46
|
-
-
|
|
47
|
-
-
|
|
50
|
+
- IMPORTANT: Always use `form-tester exec` instead of `playwright-cli` directly. This records all commands for replay. Same syntax: `form-tester exec fill e1 "value"`, `form-tester exec click e3`, `form-tester exec close` (finalizes recording).
|
|
51
|
+
- Replay a previous run: `form-tester replay output/form-id/timestamp/recording.json`
|
|
52
|
+
- IMPORTANT: All screenshots taken during a test run MUST use `--full-page` to capture the entire page, not just the viewport. This applies to every screenshot command: `form-tester exec screenshot --filename "..." --full-page`
|
|
48
53
|
- IMPORTANT: Take a full-page screenshot EVERY TIME the page changes. This includes: after clicking any action button (Neste, Forrige, Send inn, etc.), after a step/page transition, after form validation errors appear, after modals open, and after submission. Name screenshots descriptively (e.g., step1_filled.png, step2_before_submit.png, submit_result.png).
|
|
49
54
|
|
|
50
55
|
Test flow (when /test is triggered):
|
|
@@ -65,7 +70,7 @@ Dokumenter verification (only when modal confirms storage):
|
|
|
65
70
|
2. The document list loads sorted newest first. The first entry should match the form title.
|
|
66
71
|
3. Click "Se detaljer" on the first document, then click "Åpne dokumentet".
|
|
67
72
|
4. IMPORTANT - document capture depends on format:
|
|
68
|
-
- PDF documents: DOWNLOAD the file. Use `
|
|
69
|
-
- HTML documents: Take a FULL-PAGE screenshot of the ENTIRE document (`
|
|
73
|
+
- PDF documents: DOWNLOAD the file. Use `form-tester exec pdf --filename "$OUTPUT_DIR/document.pdf"` or save via browser download. Do NOT screenshot PDFs.
|
|
74
|
+
- HTML documents: Take a FULL-PAGE screenshot of the ENTIRE document (`form-tester exec screenshot --filename "$OUTPUT_DIR/document_screenshot.png" --full-page`). HTML documents cannot be downloaded as files, so the full-page screenshot is the primary artifact. Also save the snapshot and raw HTML.
|
|
70
75
|
- XML/other formats: Note the document type in test_results.txt and skip capture.
|
|
71
76
|
5. Include the document verification results in test_results.txt (document title, whether it matched the form h1, document type: HTML/PDF/XML).
|
|
@@ -20,7 +20,10 @@ form-tester install --global # or install to ~/.claude/skills/
|
|
|
20
20
|
form-tester test <url> --auto
|
|
21
21
|
form-tester test <url> --auto --pnr 12345 --persona ung-mann --scenario "test validation"
|
|
22
22
|
|
|
23
|
-
# Interactive
|
|
23
|
+
# Interactive mode (prompts for persona, scenario, etc.):
|
|
24
|
+
form-tester test <url> --human
|
|
25
|
+
|
|
26
|
+
# Full interactive CLI:
|
|
24
27
|
form-tester
|
|
25
28
|
```
|
|
26
29
|
|
|
@@ -13,16 +13,21 @@ form-tester install
|
|
|
13
13
|
## Running the CLI
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
#
|
|
17
|
-
form-tester
|
|
18
|
-
|
|
19
|
-
# Non-interactive (best for AI agents)
|
|
16
|
+
# AI mode (default) — no prompts:
|
|
20
17
|
form-tester test <url> --auto
|
|
21
18
|
form-tester test <url> --auto --pnr 12345 --persona ung-mann --scenario "test validation"
|
|
19
|
+
|
|
20
|
+
# Human mode — prompts for persona, scenario, person selection:
|
|
21
|
+
form-tester test <url> --human
|
|
22
|
+
|
|
23
|
+
# Full interactive CLI:
|
|
24
|
+
form-tester
|
|
22
25
|
```
|
|
23
26
|
|
|
24
27
|
Persona IDs: `ung-mann`, `gravid-kvinne`, `eldre-kvinne`, `kronisk-syk-mann`. Defaults to "noen" if omitted.
|
|
25
28
|
|
|
29
|
+
When the user asks for `--human` mode, use that flag. Otherwise default to `--auto`.
|
|
30
|
+
|
|
26
31
|
## Commands
|
|
27
32
|
|
|
28
33
|
| Command | Description |
|
|
@@ -36,17 +41,22 @@ Persona IDs: `ung-mann`, `gravid-kvinne`, `eldre-kvinne`, `kronisk-syk-mann`. De
|
|
|
36
41
|
| `/clear` | Clear session |
|
|
37
42
|
| `/quit` | Exit CLI |
|
|
38
43
|
|
|
39
|
-
## Playwright CLI
|
|
44
|
+
## Playwright CLI (use via form-tester exec)
|
|
45
|
+
|
|
46
|
+
IMPORTANT: Always use `form-tester exec` instead of `playwright-cli` directly. This records all commands for replay.
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
```bash
|
|
49
|
+
form-tester exec open https://example.com
|
|
50
|
+
form-tester exec snapshot
|
|
51
|
+
form-tester exec fill e1 "value"
|
|
52
|
+
form-tester exec click e3
|
|
53
|
+
form-tester exec screenshot --filename=page.png --full-page
|
|
54
|
+
form-tester exec close # finalizes recording
|
|
55
|
+
```
|
|
42
56
|
|
|
57
|
+
Replay a previous run:
|
|
43
58
|
```bash
|
|
44
|
-
|
|
45
|
-
playwright-cli snapshot
|
|
46
|
-
playwright-cli fill e1 "value"
|
|
47
|
-
playwright-cli click e3
|
|
48
|
-
playwright-cli screenshot --filename=page.png --full-page
|
|
49
|
-
playwright-cli close
|
|
59
|
+
form-tester replay output/form-id/timestamp/recording.json
|
|
50
60
|
```
|
|
51
61
|
|
|
52
62
|
## Test Flow
|
|
@@ -73,6 +83,6 @@ After submission, read the modal text:
|
|
|
73
83
|
- If it does NOT mention Dokumenter -> skip verification, note in test_results.txt.
|
|
74
84
|
|
|
75
85
|
Document capture depends on format:
|
|
76
|
-
- **PDF documents**: download the file (`
|
|
77
|
-
- **HTML documents**: take a full-page screenshot of the ENTIRE document (`
|
|
86
|
+
- **PDF documents**: download the file (`form-tester exec pdf --filename "..." `). Do NOT screenshot PDFs.
|
|
87
|
+
- **HTML documents**: take a full-page screenshot of the ENTIRE document (`form-tester exec screenshot --filename "..." --full-page`). HTML documents cannot be downloaded, so the screenshot is the primary artifact.
|
|
78
88
|
- **XML/other**: note the type in test_results.txt and skip capture.
|
package/README.md
CHANGED
|
@@ -32,20 +32,41 @@ Edit `form-tester.config.json` and set your `pnr`.
|
|
|
32
32
|
|
|
33
33
|
## Usage
|
|
34
34
|
|
|
35
|
-
###
|
|
36
|
-
|
|
37
|
-
AI agents (Claude Code, Copilot) will use `--auto` mode by default. No prompts, just runs the test:
|
|
35
|
+
### Test modes
|
|
38
36
|
|
|
39
37
|
```bash
|
|
38
|
+
# AI mode (default) — no prompts, uses defaults:
|
|
40
39
|
form-tester test <url> --auto
|
|
41
40
|
form-tester test <url> --auto --pnr 12345 --persona ung-mann --scenario "test validation"
|
|
41
|
+
|
|
42
|
+
# Human mode — prompts for persona, scenario, person selection:
|
|
43
|
+
form-tester test <url> --human
|
|
44
|
+
|
|
45
|
+
# Full interactive CLI:
|
|
46
|
+
form-tester
|
|
42
47
|
```
|
|
43
48
|
|
|
44
49
|
Persona IDs: `ung-mann`, `gravid-kvinne`, `eldre-kvinne`, `kronisk-syk-mann`
|
|
45
50
|
|
|
51
|
+
### Recording & Replay
|
|
52
|
+
|
|
53
|
+
Every test run records all commands to `recording.json`. Use `form-tester exec` instead of `playwright-cli` to ensure all commands are recorded:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
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
|
+
```
|
|
61
|
+
|
|
62
|
+
Replay a previous run:
|
|
63
|
+
```bash
|
|
64
|
+
form-tester replay output/form-id/timestamp/recording.json
|
|
65
|
+
```
|
|
66
|
+
|
|
46
67
|
### Interactive CLI
|
|
47
68
|
|
|
48
|
-
|
|
69
|
+
Full interactive CLI with all commands:
|
|
49
70
|
|
|
50
71
|
```bash
|
|
51
72
|
form-tester
|
package/form-tester.js
CHANGED
|
@@ -6,7 +6,7 @@ const { spawn, execSync } = require("child_process");
|
|
|
6
6
|
|
|
7
7
|
const CONFIG_PATH = path.join(process.cwd(), "form-tester.config.json");
|
|
8
8
|
const OUTPUT_BASE = path.resolve(process.cwd(), "output");
|
|
9
|
-
const LOCAL_VERSION = "0.7.
|
|
9
|
+
const LOCAL_VERSION = "0.7.2";
|
|
10
10
|
const RECOMMENDED_PERSON = "Uromantisk Direktør";
|
|
11
11
|
|
|
12
12
|
// Recording — persisted to disk so `form-tester exec` can append across processes
|
|
@@ -1300,6 +1300,17 @@ async function main() {
|
|
|
1300
1300
|
process.exit(0);
|
|
1301
1301
|
}
|
|
1302
1302
|
|
|
1303
|
+
if (args[0] === "test" && args.includes("--human")) {
|
|
1304
|
+
const config = loadConfig();
|
|
1305
|
+
const url = args.find((a) => a.startsWith("http"));
|
|
1306
|
+
if (!url) {
|
|
1307
|
+
console.error("Usage: form-tester test <url> --human");
|
|
1308
|
+
process.exit(1);
|
|
1309
|
+
}
|
|
1310
|
+
await handleTest(url, config);
|
|
1311
|
+
process.exit(0);
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1303
1314
|
if (args[0] === "test" && args.includes("--auto")) {
|
|
1304
1315
|
const config = loadConfig();
|
|
1305
1316
|
const url = args.find((a) => a.startsWith("http"));
|
|
@@ -1362,5 +1373,8 @@ module.exports = {
|
|
|
1362
1373
|
getPersonaById,
|
|
1363
1374
|
formatPersonaList,
|
|
1364
1375
|
promptScenario,
|
|
1376
|
+
startRecording,
|
|
1377
|
+
appendToRecording,
|
|
1378
|
+
finalizeRecording,
|
|
1365
1379
|
};
|
|
1366
1380
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const test = require("node:test");
|
|
2
2
|
const assert = require("node:assert/strict");
|
|
3
3
|
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const os = require("node:os");
|
|
7
|
+
|
|
4
8
|
const {
|
|
5
9
|
extractFormId,
|
|
6
10
|
extractPnrFromUrl,
|
|
@@ -14,6 +18,9 @@ const {
|
|
|
14
18
|
getPersonaById,
|
|
15
19
|
formatPersonaList,
|
|
16
20
|
promptScenario,
|
|
21
|
+
startRecording,
|
|
22
|
+
appendToRecording,
|
|
23
|
+
finalizeRecording,
|
|
17
24
|
} = require("../form-tester");
|
|
18
25
|
|
|
19
26
|
test("extractFormId returns form id from skjemautfyller URL", () => {
|
|
@@ -118,3 +125,58 @@ test("each persona has a unique id", () => {
|
|
|
118
125
|
test("promptScenario is exported as a function", () => {
|
|
119
126
|
assert.equal(typeof promptScenario, "function");
|
|
120
127
|
});
|
|
128
|
+
|
|
129
|
+
// --- Recording tests ---
|
|
130
|
+
|
|
131
|
+
function makeTmpDir() {
|
|
132
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), "form-tester-test-"));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
test("startRecording creates recording.json with empty commands", () => {
|
|
136
|
+
const dir = makeTmpDir();
|
|
137
|
+
const filePath = startRecording(dir);
|
|
138
|
+
assert.equal(filePath, path.join(dir, "recording.json"));
|
|
139
|
+
const data = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
140
|
+
assert.equal(data.commandCount, 0);
|
|
141
|
+
assert.deepEqual(data.commands, []);
|
|
142
|
+
assert.ok(data.startedAt);
|
|
143
|
+
assert.equal(data.completedAt, null);
|
|
144
|
+
fs.rmSync(dir, { recursive: true });
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("appendToRecording adds commands to recording file", () => {
|
|
148
|
+
const dir = makeTmpDir();
|
|
149
|
+
const filePath = startRecording(dir);
|
|
150
|
+
appendToRecording(filePath, ["open", "https://example.com"]);
|
|
151
|
+
appendToRecording(filePath, ["fill", "e1", "hello"]);
|
|
152
|
+
appendToRecording(filePath, ["click", "e3"]);
|
|
153
|
+
const data = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
154
|
+
assert.equal(data.commandCount, 3);
|
|
155
|
+
assert.deepEqual(data.commands[0].args, ["open", "https://example.com"]);
|
|
156
|
+
assert.deepEqual(data.commands[1].args, ["fill", "e1", "hello"]);
|
|
157
|
+
assert.deepEqual(data.commands[2].args, ["click", "e3"]);
|
|
158
|
+
assert.ok(data.commands[0].timestamp);
|
|
159
|
+
fs.rmSync(dir, { recursive: true });
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("finalizeRecording sets completedAt timestamp", () => {
|
|
163
|
+
const dir = makeTmpDir();
|
|
164
|
+
const filePath = startRecording(dir);
|
|
165
|
+
appendToRecording(filePath, ["snapshot"]);
|
|
166
|
+
const result = finalizeRecording(filePath);
|
|
167
|
+
assert.equal(result, filePath);
|
|
168
|
+
const data = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
169
|
+
assert.ok(data.completedAt);
|
|
170
|
+
assert.equal(data.commandCount, 1);
|
|
171
|
+
fs.rmSync(dir, { recursive: true });
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("finalizeRecording returns null for missing file", () => {
|
|
175
|
+
assert.equal(finalizeRecording("/nonexistent/recording.json"), null);
|
|
176
|
+
assert.equal(finalizeRecording(null), null);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("appendToRecording is resilient to missing file", () => {
|
|
180
|
+
// Should not throw
|
|
181
|
+
appendToRecording("/nonexistent/recording.json", ["click", "e1"]);
|
|
182
|
+
});
|