form-tester 0.7.3 → 0.8.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.
@@ -69,22 +69,27 @@ Dokumenter verification (only when modal confirms storage):
69
69
  1. Navigate to `/dokumenter?pnr={PNR}` and select the same person used during form fill.
70
70
  2. The document list loads sorted newest first. The first entry should match the form title.
71
71
  3. Click "Se detaljer" on the first document, then click "Åpne dokumentet".
72
- 4. IMPORTANT - document capture depends on format:
73
-
74
- PDF documents (shown in a PDF viewer/modal/iframe):
75
- Do NOT screenshot PDFs. Instead, download the actual PDF file:
76
- a. Take a snapshot to find the PDF viewer element: `form-tester exec snapshot`
77
- b. Find the iframe or embed/object element that displays the PDF. Look for src attributes containing .pdf or blob: URLs.
78
- c. Extract the PDF URL: `form-tester exec eval "document.querySelector('iframe')?.src || document.querySelector('embed')?.src || document.querySelector('object')?.data"`
79
- d. If the URL is a blob: URL or direct PDF link, download it: `form-tester exec eval "async () => { const r = await fetch(document.querySelector('iframe')?.src); const b = await r.blob(); return URL.createObjectURL(b); }"`
80
- e. Or use the download button if the PDF viewer has one — look for a download icon/button in the snapshot and click it.
81
- f. Save the PDF: `form-tester exec pdf --filename "$OUTPUT_DIR/document.pdf"`
82
- g. If all else fails, right-click save or use: `form-tester exec run-code "async page => { const frame = page.frameLocator('iframe').first(); /* extract content */ }"`
83
-
84
- HTML documents (opens in a new tab or renders in page):
85
- 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 with:
86
- `form-tester exec eval "document.documentElement.outerHTML"` and save to document.html.
87
-
88
- XML/other formats: Note the document type in test_results.txt and skip capture.
72
+ 4. After clicking "Åpne dokumentet", the document may open in a dialog, a new tab, or inline. FIRST determine the format before capturing:
73
+
74
+ Step A Detect format:
75
+ Run `form-tester exec snapshot` and examine the result.
76
+ - If you see an iframe/embed/object with a src containing `.pdf`, `blob:`, or a PDF viewer it's a PDF.
77
+ - If you see rendered HTML content (headings, paragraphs, form data) it's HTML.
78
+ - If `--full-page` screenshot times out it's almost certainly a PDF viewer. Do NOT retry the screenshot. Switch to PDF download.
79
+
80
+ Step B PDF documents (viewer in dialog/modal/iframe/new tab):
81
+ Do NOT screenshot PDFs it will timeout or produce garbage. Download the file:
82
+ 1. Extract PDF URL from the iframe/embed/object:
83
+ `form-tester exec eval "document.querySelector('iframe')?.src || document.querySelector('embed')?.src || document.querySelector('object')?.data"`
84
+ 2. If the result is a URL, download it with run-code:
85
+ `form-tester exec run-code "async page => { const url = await page.evaluate(() => document.querySelector('iframe')?.src || document.querySelector('embed')?.src || document.querySelector('object')?.data); if (url) { const resp = await page.request.get(url); require('fs').writeFileSync('$OUTPUT_DIR/document.pdf', await resp.body()); } }"`
86
+ 3. Or if the PDF viewer has a download button, click it.
87
+ 4. Record in test_results.txt: document type PDF, downloaded to document.pdf.
88
+
89
+ Step C — HTML documents:
90
+ Take a FULL-PAGE screenshot (`form-tester exec screenshot --filename "$OUTPUT_DIR/document_screenshot.png" --full-page`).
91
+ Also save raw HTML: `form-tester exec eval "document.documentElement.outerHTML"` → save to document.html.
92
+
93
+ Step D — XML/other: Note type in test_results.txt, skip capture.
89
94
 
90
95
  5. Include the document verification results in test_results.txt (document title, whether it matched the form h1, document type: HTML/PDF/XML).
@@ -82,13 +82,14 @@ After submission, read the modal text:
82
82
  - If it mentions Dokumenter storage -> navigate to `/dokumenter?pnr={PNR}`, verify the document appears.
83
83
  - If it does NOT mention Dokumenter -> skip verification, note in test_results.txt.
84
84
 
85
- Document capture depends on format:
85
+ Document capture FIRST detect the format by running `form-tester exec snapshot`:
86
86
 
87
- **PDF documents** (shown in PDF viewer/modal/iframe): Do NOT screenshot PDFs. Download the file instead:
88
- 1. Take a snapshot to find the PDF viewer: `form-tester exec snapshot`
89
- 2. Extract the PDF URL from the iframe/embed: `form-tester exec eval "document.querySelector('iframe')?.src || document.querySelector('embed')?.src || document.querySelector('object')?.data"`
90
- 3. Download via: `form-tester exec pdf --filename "$OUTPUT_DIR/document.pdf"` or click the download button in the PDF viewer if available.
87
+ **PDF documents** (iframe/embed with .pdf or blob: URL, or screenshot times out): Do NOT screenshot PDFs. Download instead:
88
+ 1. Extract URL: `form-tester exec eval "document.querySelector('iframe')?.src || document.querySelector('embed')?.src || document.querySelector('object')?.data"`
89
+ 2. Download: `form-tester exec run-code "async page => { const url = await page.evaluate(() => document.querySelector('iframe')?.src || document.querySelector('embed')?.src || document.querySelector('object')?.data); if (url) { const resp = await page.request.get(url); require('fs').writeFileSync('OUTPUT_DIR/document.pdf', await resp.body()); } }"`
90
+ 3. Or click the download button in the PDF viewer if available.
91
+ 4. If `--full-page` screenshot times out, it's a PDF — switch to download, don't retry screenshot.
91
92
 
92
- **HTML documents**: take a full-page screenshot of the ENTIRE document (`form-tester exec screenshot --filename "..." --full-page`). Also save raw HTML with `form-tester exec eval "document.documentElement.outerHTML"`.
93
+ **HTML documents**: `form-tester exec screenshot --filename "..." --full-page`. Also save raw HTML.
93
94
 
94
95
  **XML/other**: note the type in test_results.txt and skip capture.
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.3";
9
+ const LOCAL_VERSION = "0.8.1";
10
10
  const RECOMMENDED_PERSON = "Uromantisk Direktør";
11
11
 
12
12
  // Recording — persisted to disk so `form-tester exec` can append across processes
@@ -466,18 +466,26 @@ function clearConsole() {
466
466
  function printHelp() {
467
467
  console.log(
468
468
  [
469
- "Commands:",
470
- " /setup Install Playwright CLI + skills if missing",
471
- " /update Update repo (if git), Playwright CLI, and skills",
472
- " /version Show local skill version",
469
+ "",
470
+ "Subcommands (run directly):",
471
+ " form-tester install [--global] Install skill files into project or ~/.claude/skills/",
472
+ " form-tester test <url> --auto Non-interactive test (for AI agents)",
473
+ " form-tester test <url> --human Interactive test with prompts",
474
+ " form-tester exec <command> [args] Run playwright-cli command (recorded)",
475
+ " form-tester replay <recording.json> Replay a recorded test run",
476
+ "",
477
+ "Interactive commands:",
478
+ " /test {url} Open form URL and start test",
479
+ " /save {label} Save snapshot + screenshot to output folder",
473
480
  " /people Scan visible person list and prompt selection",
474
481
  " /persona List available personas",
475
- " /test {url} Open form URL with Playwright CLI and save initial artifacts",
476
- " /save {label} Save snapshot + screenshot to last output folder",
482
+ " /recording Show active recording status",
483
+ " /setup Install Playwright CLI + skills if missing",
484
+ " /update Update Playwright CLI and skills",
485
+ " /version Show version",
477
486
  " /clear Clear the console",
478
487
  " /help Show this help",
479
- " /exit Exit the app",
480
- " /quit Exit the app",
488
+ " /quit Exit",
481
489
  ].join("\n"),
482
490
  );
483
491
  }
@@ -955,12 +963,10 @@ async function handleTest(url, config) {
955
963
  "/dokumenter?pnr={PNR}",
956
964
  );
957
965
 
958
- // Save recording
959
- const recordingPath = saveRecording();
960
- if (recordingPath) {
961
- console.log(`Recording saved: ${recordingPath}`);
962
- console.log(`Replay with: form-tester replay "${recordingPath}"`);
963
- }
966
+ // Don't finalize recording — exec commands will keep appending.
967
+ console.log(`Recording active: ${config.activeRecording}`);
968
+ console.log(`Use 'form-tester exec' for all playwright-cli commands to record them.`);
969
+ console.log(`Recording finalizes on 'form-tester exec close'.`);
964
970
  }
965
971
 
966
972
  async function handleTestAuto(url, config, flags) {
@@ -1073,12 +1079,11 @@ async function handleTestAuto(url, config, flags) {
1073
1079
  printNextSteps(outputDir, dokumenterUrl || "/dokumenter?pnr={PNR}");
1074
1080
  }
1075
1081
 
1076
- // Save recording
1077
- const recordingPath = saveRecording();
1078
- if (recordingPath) {
1079
- log(`Recording saved: ${recordingPath}`);
1080
- log(`Replay with: form-tester replay "${recordingPath}"`);
1081
- }
1082
+ // Don't finalize recording here — `form-tester exec` commands will keep appending.
1083
+ // Recording is finalized when `form-tester exec close` is called.
1084
+ log(`Recording active: ${config.activeRecording}`);
1085
+ log(`Use 'form-tester exec' for all playwright-cli commands to record them.`);
1086
+ log(`Recording finalizes on 'form-tester exec close'.`);
1082
1087
  }
1083
1088
 
1084
1089
  async function handleReplay(filePath) {
@@ -1140,6 +1145,18 @@ async function handleCommand(line, config) {
1140
1145
  await saveArtifacts(config, label);
1141
1146
  break;
1142
1147
  }
1148
+ case "/recording": {
1149
+ const rec = config.activeRecording;
1150
+ if (rec && fs.existsSync(rec)) {
1151
+ const data = JSON.parse(fs.readFileSync(rec, "utf8"));
1152
+ console.log(`Active recording: ${rec}`);
1153
+ console.log(`Commands recorded: ${data.commandCount}`);
1154
+ console.log(`Started: ${data.startedAt}`);
1155
+ } else {
1156
+ console.log("No active recording. Start a test with /test to begin recording.");
1157
+ }
1158
+ break;
1159
+ }
1143
1160
  case "/clear":
1144
1161
  case "/cls":
1145
1162
  clearConsole();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form-tester",
3
- "version": "0.7.3",
3
+ "version": "0.8.1",
4
4
  "description": "AI-powered form testing skill for /skjemautfyller forms using Playwright CLI. Works with Claude Code and GitHub Copilot.",
5
5
  "main": "form-tester.js",
6
6
  "bin": {