form-tester 0.3.5 → 0.4.1
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/.claude/skills/form-tester/INSTRUCTIONS.md +15 -5
- package/.claude/skills/form-tester/SKILL.md +16 -4
- package/.github/copilot-instructions.md +14 -9
- package/README.md +30 -19
- package/form-tester.js +101 -2
- package/package.json +1 -1
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
# Form Tester Skill Instructions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Install (user runs once):
|
|
4
4
|
```
|
|
5
|
-
|
|
5
|
+
npm install -g form-tester
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
Install skill files:
|
|
9
|
+
```
|
|
10
|
+
form-tester install
|
|
6
11
|
```
|
|
7
12
|
|
|
8
13
|
Run the CLI:
|
|
9
14
|
```
|
|
10
|
-
|
|
15
|
+
form-tester
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Non-interactive mode (best for AI agents):
|
|
19
|
+
```
|
|
20
|
+
form-tester test <url> --auto
|
|
21
|
+
form-tester test <url> --auto --pnr 12345 --persona ung-mann
|
|
11
22
|
```
|
|
12
23
|
|
|
13
24
|
Commands:
|
|
@@ -23,7 +34,7 @@ Commands:
|
|
|
23
34
|
```
|
|
24
35
|
|
|
25
36
|
Notes:
|
|
26
|
-
- New users:
|
|
37
|
+
- New users: run `npm install -g form-tester` then `form-tester install` in your project.
|
|
27
38
|
- Provide a full /skjemautfyller URL. If `pnr` is missing, the CLI will prompt.
|
|
28
39
|
- The CLI opens the form with Playwright CLI, saves an initial snapshot + screenshot, and prints next-step commands.
|
|
29
40
|
- Use `/save {label}` to capture additional snapshots + screenshots into the same output folder.
|
|
@@ -56,4 +67,3 @@ Dokumenter verification (only when modal confirms storage):
|
|
|
56
67
|
5. If the document opens as a PDF viewer: download the PDF instead of screenshotting. Use `playwright-cli pdf --filename "$OUTPUT_DIR/document.pdf"` or save it via the download.
|
|
57
68
|
6. If the document does NOT open (XML format, no new tab, or other): note the document type in test_results.txt and skip the screenshot/download.
|
|
58
69
|
7. Include the document verification results in test_results.txt (document title, whether it matched the form h1, document type: HTML/PDF/XML).
|
|
59
|
-
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: form-tester
|
|
3
3
|
description: Runs the form-tester CLI to test /skjemautfyller forms via Playwright CLI and exposes playwright-cli commands.
|
|
4
|
-
allowed-tools: Bash(powershell:*), Bash(playwright-cli:*), Bash(
|
|
4
|
+
allowed-tools: Bash(powershell:*), Bash(playwright-cli:*), Bash(form-tester:*)
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Form Tester CLI
|
|
@@ -9,10 +9,23 @@ allowed-tools: Bash(powershell:*), Bash(playwright-cli:*), Bash(npx form-tester:
|
|
|
9
9
|
## Quick start
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
# One-time install (user runs this manually):
|
|
13
|
+
npm install -g form-tester
|
|
14
|
+
|
|
15
|
+
# Install skill files into project:
|
|
16
|
+
form-tester install
|
|
17
|
+
form-tester install --global # or install to ~/.claude/skills/
|
|
18
|
+
|
|
19
|
+
# Non-interactive mode (no prompts, best for AI agents):
|
|
20
|
+
form-tester test <url> --auto
|
|
21
|
+
form-tester test <url> --auto --pnr 12345 --persona ung-mann --scenario "test validation"
|
|
22
|
+
|
|
23
|
+
# Interactive CLI:
|
|
24
|
+
form-tester
|
|
14
25
|
```
|
|
15
26
|
|
|
27
|
+
Persona IDs: `ung-mann`, `gravid-kvinne`, `eldre-kvinne`, `kronisk-syk-mann`. Defaults to "noen" (neutral answers) if omitted.
|
|
28
|
+
|
|
16
29
|
## Commands
|
|
17
30
|
|
|
18
31
|
```bash
|
|
@@ -37,4 +50,3 @@ Use `/people` to rescan the visible person list and get a numbered selection pro
|
|
|
37
50
|
## Playwright CLI
|
|
38
51
|
|
|
39
52
|
You can also run `playwright-cli` commands directly when needed.
|
|
40
|
-
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
# Form Tester — Copilot Instructions
|
|
2
2
|
|
|
3
|
-
You have access to a form-testing CLI tool (`form-tester
|
|
3
|
+
You have access to a form-testing CLI tool (`form-tester`) that automates testing of /skjemautfyller forms using Playwright CLI.
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
7
|
+
User must install globally first:
|
|
7
8
|
```bash
|
|
8
|
-
|
|
9
|
+
npm install -g form-tester
|
|
10
|
+
form-tester install
|
|
9
11
|
```
|
|
10
12
|
|
|
11
13
|
## Running the CLI
|
|
12
14
|
|
|
13
15
|
```bash
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
+
# Interactive
|
|
17
|
+
form-tester
|
|
16
18
|
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
+
# Non-interactive (best for AI agents)
|
|
20
|
+
form-tester test <url> --auto
|
|
21
|
+
form-tester test <url> --auto --pnr 12345 --persona ung-mann --scenario "test validation"
|
|
19
22
|
```
|
|
20
23
|
|
|
24
|
+
Persona IDs: `ung-mann`, `gravid-kvinne`, `eldre-kvinne`, `kronisk-syk-mann`. Defaults to "noen" if omitted.
|
|
25
|
+
|
|
21
26
|
## Commands
|
|
22
27
|
|
|
23
28
|
| Command | Description |
|
|
@@ -58,10 +63,10 @@ When `/test` is triggered:
|
|
|
58
63
|
- Provide a full /skjemautfyller URL. If `pnr` is missing, the CLI will prompt.
|
|
59
64
|
- All screenshots MUST use `--full-page` to capture the entire page.
|
|
60
65
|
- Use `/save {label}` to capture additional snapshots into the output folder.
|
|
61
|
-
- If an error modal appears on submit, open DevTools
|
|
66
|
+
- If an error modal appears on submit, open DevTools -> Network, retry once, and capture the Correlation ID header.
|
|
62
67
|
|
|
63
68
|
## Post-Submit Verification
|
|
64
69
|
|
|
65
70
|
After submission, read the modal text:
|
|
66
|
-
- If it mentions Dokumenter storage
|
|
67
|
-
- If it does NOT mention Dokumenter
|
|
71
|
+
- If it mentions Dokumenter storage -> navigate to `/dokumenter?pnr={PNR}`, verify the document appears, and capture it (screenshot for HTML, download for PDF).
|
|
72
|
+
- If it does NOT mention Dokumenter -> skip verification, note in test_results.txt.
|
package/README.md
CHANGED
|
@@ -2,23 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
AI-powered testing skill for `/skjemautfyller` forms using [Playwright CLI](https://www.npmjs.com/package/@playwright/cli). Works with **Claude Code** and **GitHub Copilot**.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
npm install -g form-tester
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Then in your project:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
form-tester install # project-level (commits to repo)
|
|
15
|
+
form-tester install --global # personal (~/.claude/skills/)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This installs:
|
|
12
19
|
- `.claude/skills/form-tester/` — Claude Code skill
|
|
13
20
|
- `.claude/skills/playwright-cli/` — Playwright CLI skill
|
|
14
21
|
- `.github/copilot-instructions.md` — GitHub Copilot instructions
|
|
15
22
|
- `form-tester.config.example.json` — Config template
|
|
16
|
-
|
|
17
|
-
## Prerequisites
|
|
18
|
-
|
|
19
|
-
- Node.js 18+
|
|
20
|
-
|
|
21
|
-
Playwright CLI is included as a dependency — no separate install needed.
|
|
23
|
+
- `playwright-cli` globally (if not already installed)
|
|
22
24
|
|
|
23
25
|
## Configuration
|
|
24
26
|
|
|
@@ -30,27 +32,30 @@ Edit `form-tester.config.json` and set your `pnr`.
|
|
|
30
32
|
|
|
31
33
|
## Usage
|
|
32
34
|
|
|
33
|
-
###
|
|
34
|
-
|
|
35
|
-
The skill is automatically detected when you open the project in Claude Code. Use the `/form-tester` skill or run:
|
|
35
|
+
### Non-interactive (recommended for AI agents)
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
|
|
38
|
+
form-tester test <url> --auto
|
|
39
|
+
form-tester test <url> --auto --pnr 12345 --persona ung-mann --scenario "test validation"
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Copilot reads instructions from `.github/copilot-instructions.md` automatically. Open the project in VS Code with Copilot enabled.
|
|
42
|
+
Persona IDs: `ung-mann`, `gravid-kvinne`, `eldre-kvinne`, `kronisk-syk-mann`
|
|
44
43
|
|
|
45
|
-
###
|
|
44
|
+
### Interactive CLI
|
|
46
45
|
|
|
47
46
|
```bash
|
|
48
|
-
|
|
47
|
+
form-tester
|
|
49
48
|
```
|
|
50
49
|
|
|
51
50
|
Commands: `/setup`, `/update`, `/version`, `/people`, `/test {url}`, `/save {label}`, `/clear`, `/quit`
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
### Claude Code
|
|
53
|
+
|
|
54
|
+
The skill is automatically detected when you open the project. Use the `/form-tester` skill.
|
|
55
|
+
|
|
56
|
+
### GitHub Copilot
|
|
57
|
+
|
|
58
|
+
Copilot reads instructions from `.github/copilot-instructions.md` automatically.
|
|
54
59
|
|
|
55
60
|
## Test Output
|
|
56
61
|
|
|
@@ -59,6 +64,12 @@ Test runs are saved to `output/{form-id}/{timestamp}/` with:
|
|
|
59
64
|
- Screenshots (PNG, full-page)
|
|
60
65
|
- `test_results.txt`
|
|
61
66
|
|
|
67
|
+
## Update
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm update -g form-tester
|
|
71
|
+
```
|
|
72
|
+
|
|
62
73
|
## Development
|
|
63
74
|
|
|
64
75
|
```bash
|
package/form-tester.js
CHANGED
|
@@ -6,7 +6,7 @@ const { spawn, execSync } = require("child_process");
|
|
|
6
6
|
|
|
7
7
|
const CONFIG_PATH = path.join(__dirname, "form-tester.config.json");
|
|
8
8
|
const OUTPUT_BASE = path.resolve(__dirname, "output");
|
|
9
|
-
const LOCAL_VERSION = "0.
|
|
9
|
+
const LOCAL_VERSION = "0.4.1";
|
|
10
10
|
const RECOMMENDED_PERSON = "Uromantisk Direktør";
|
|
11
11
|
|
|
12
12
|
const PERSONAS = [
|
|
@@ -878,6 +878,91 @@ async function handleTest(url, config) {
|
|
|
878
878
|
);
|
|
879
879
|
}
|
|
880
880
|
|
|
881
|
+
async function handleTestAuto(url, config, flags) {
|
|
882
|
+
// Resolve PNR
|
|
883
|
+
const pnr = flags.pnr || config.pnr;
|
|
884
|
+
if (!pnr) {
|
|
885
|
+
console.error("No PNR available. Pass --pnr <value> or set it in form-tester.config.json");
|
|
886
|
+
process.exit(1);
|
|
887
|
+
}
|
|
888
|
+
const fullUrl = extractPnrFromUrl(url) ? url : setPnrOnUrl(url, pnr);
|
|
889
|
+
config.pnr = pnr;
|
|
890
|
+
saveConfig(config);
|
|
891
|
+
|
|
892
|
+
// Resolve persona
|
|
893
|
+
let personaChoice;
|
|
894
|
+
const personaId = flags.persona;
|
|
895
|
+
if (personaId) {
|
|
896
|
+
const found = getPersonaById(personaId);
|
|
897
|
+
if (found) {
|
|
898
|
+
console.log(`Persona: ${found.name} — ${found.description}`);
|
|
899
|
+
personaChoice = { type: "preset", persona: found };
|
|
900
|
+
} else {
|
|
901
|
+
console.log(`Unknown persona "${personaId}", using Noen.`);
|
|
902
|
+
personaChoice = { type: "noen", persona: null };
|
|
903
|
+
}
|
|
904
|
+
} else {
|
|
905
|
+
console.log("Persona: Noen — nøytrale svar (auto)");
|
|
906
|
+
personaChoice = { type: "noen", persona: null };
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Resolve scenario
|
|
910
|
+
const scenarioChoice = flags.scenario
|
|
911
|
+
? { type: "custom", description: flags.scenario }
|
|
912
|
+
: { type: "default", description: "Standard test" };
|
|
913
|
+
console.log(`Scenario: ${scenarioChoice.description}`);
|
|
914
|
+
|
|
915
|
+
// Create output directory
|
|
916
|
+
const formId = sanitizeSegment(extractFormId(fullUrl));
|
|
917
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
918
|
+
const outputDir = path.join(OUTPUT_BASE, formId, timestamp);
|
|
919
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
920
|
+
|
|
921
|
+
config.lastTestUrl = fullUrl;
|
|
922
|
+
config.lastRunDir = outputDir;
|
|
923
|
+
saveConfig(config);
|
|
924
|
+
|
|
925
|
+
// Save persona and scenario
|
|
926
|
+
if (personaChoice.type === "preset") {
|
|
927
|
+
fs.writeFileSync(path.join(outputDir, "persona.json"), JSON.stringify(personaChoice.persona, null, 2));
|
|
928
|
+
} else {
|
|
929
|
+
fs.writeFileSync(path.join(outputDir, "persona.json"), JSON.stringify(
|
|
930
|
+
{ id: "noen", name: "Noen", description: "Nøytrale svar", traits: {} }, null, 2,
|
|
931
|
+
));
|
|
932
|
+
}
|
|
933
|
+
fs.writeFileSync(path.join(outputDir, "scenario.json"), JSON.stringify(scenarioChoice, null, 2));
|
|
934
|
+
|
|
935
|
+
// Open and snapshot
|
|
936
|
+
console.log("Opening form with Playwright CLI...");
|
|
937
|
+
await runPlaywrightCli(["open", fullUrl]);
|
|
938
|
+
await runPlaywrightCli(["snapshot", "--filename", path.join(outputDir, "page_open.yml")]);
|
|
939
|
+
await runPlaywrightCli(["screenshot", "--filename", path.join(outputDir, "page_open.png")]);
|
|
940
|
+
|
|
941
|
+
// Auto-select person (try recommended, then first available)
|
|
942
|
+
let options = extractPersonsFromSnapshotFile(path.join(outputDir, "page_open.yml"));
|
|
943
|
+
if (!options.length) {
|
|
944
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
945
|
+
await sleep(1500);
|
|
946
|
+
options = await fetchPersonOptions();
|
|
947
|
+
if (options.length) break;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
if (options.length) {
|
|
951
|
+
options = prioritizeRecommended(options, RECOMMENDED_PERSON);
|
|
952
|
+
const chosen = options[0];
|
|
953
|
+
console.log(`Auto-selected person: ${chosen}`);
|
|
954
|
+
config.lastPerson = chosen;
|
|
955
|
+
saveConfig(config);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
const dokumenterUrl = resolveDokumenterUrl(config);
|
|
959
|
+
console.log(`Output folder: ${outputDir}`);
|
|
960
|
+
if (dokumenterUrl) {
|
|
961
|
+
console.log(`Dokumenter URL: ${dokumenterUrl}`);
|
|
962
|
+
}
|
|
963
|
+
printNextSteps(outputDir, dokumenterUrl || "/dokumenter?pnr={PNR}");
|
|
964
|
+
}
|
|
965
|
+
|
|
881
966
|
async function handleCommand(line, config) {
|
|
882
967
|
const trimmed = line.trim();
|
|
883
968
|
if (!trimmed) return;
|
|
@@ -1008,7 +1093,7 @@ function install(targetDir, isGlobal) {
|
|
|
1008
1093
|
console.log("\nDone! Next steps:");
|
|
1009
1094
|
console.log(" 1. cp form-tester.config.example.json form-tester.config.json");
|
|
1010
1095
|
console.log(' 2. Edit form-tester.config.json and set your "pnr"');
|
|
1011
|
-
console.log(" 3. Run:
|
|
1096
|
+
console.log(" 3. Run: form-tester");
|
|
1012
1097
|
}
|
|
1013
1098
|
|
|
1014
1099
|
async function main() {
|
|
@@ -1031,6 +1116,20 @@ async function main() {
|
|
|
1031
1116
|
process.exit(0);
|
|
1032
1117
|
}
|
|
1033
1118
|
|
|
1119
|
+
if (args[0] === "test" && args.includes("--auto")) {
|
|
1120
|
+
const config = loadConfig();
|
|
1121
|
+
const url = args.find((a) => a.startsWith("http"));
|
|
1122
|
+
if (!url) {
|
|
1123
|
+
console.error("Usage: form-tester test <url> --auto [--pnr <pnr>] [--persona <id>] [--scenario <text>]");
|
|
1124
|
+
process.exit(1);
|
|
1125
|
+
}
|
|
1126
|
+
const pnrFlag = args[args.indexOf("--pnr") + 1];
|
|
1127
|
+
const personaFlag = args[args.indexOf("--persona") + 1];
|
|
1128
|
+
const scenarioFlag = args[args.indexOf("--scenario") + 1];
|
|
1129
|
+
await handleTestAuto(url, config, { pnr: pnrFlag, persona: personaFlag, scenario: scenarioFlag });
|
|
1130
|
+
process.exit(0);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1034
1133
|
const config = loadConfig();
|
|
1035
1134
|
await handleVersionMismatch(config);
|
|
1036
1135
|
|
package/package.json
CHANGED