form-tester 0.3.5 → 0.4.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/.claude/skills/form-tester/SKILL.md +7 -1
- package/form-tester.js +100 -1
- package/package.json +1 -1
|
@@ -10,9 +10,15 @@ allowed-tools: Bash(powershell:*), Bash(playwright-cli:*), Bash(npx form-tester:
|
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
npx form-tester install # one-time setup
|
|
13
|
-
npx form-tester #
|
|
13
|
+
npx form-tester # interactive CLI
|
|
14
|
+
|
|
15
|
+
# Non-interactive mode (no prompts, best for AI agents):
|
|
16
|
+
npx form-tester test <url> --auto
|
|
17
|
+
npx form-tester test <url> --auto --pnr 12345 --persona ung-mann --scenario "test validation"
|
|
14
18
|
```
|
|
15
19
|
|
|
20
|
+
Persona IDs: `ung-mann`, `gravid-kvinne`, `eldre-kvinne`, `kronisk-syk-mann`. Defaults to "noen" (neutral answers) if omitted.
|
|
21
|
+
|
|
16
22
|
## Commands
|
|
17
23
|
|
|
18
24
|
```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.0";
|
|
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;
|
|
@@ -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