form-tester 0.7.0 → 0.7.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.
@@ -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 CLI:
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
 
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.0";
9
+ const LOCAL_VERSION = "0.7.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
@@ -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,6 @@
1
1
  {
2
2
  "name": "form-tester",
3
- "version": "0.7.0",
3
+ "version": "0.7.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": {
@@ -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
+ });