form-tester 0.10.3 → 0.11.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.
@@ -5,9 +5,10 @@ Install (user runs once):
5
5
  npm install -g form-tester
6
6
  ```
7
7
 
8
- Install skill files:
8
+ Install skill files and configure:
9
9
  ```
10
10
  form-tester install
11
+ form-tester init # set baseUrl, pnr, person, etc.
11
12
  ```
12
13
 
13
14
  Test modes:
@@ -71,10 +72,13 @@ IMPORTANT: Each prompt below MUST be asked as a separate message to the user. Wa
71
72
  4. Only after receiving answers to all prompts, proceed with the steps below.
72
73
 
73
74
  Step 1 — Open and setup:
74
- If the user gives a partial URL (e.g. `skjemautfyller/SLV-PasRapp-2020`), read `form-tester.config.json` to get `baseUrl` and `pnr`. Construct the full URL as `{baseUrl}/{path}?pnr={pnr}`. Do NOT guess the domain.
75
+ You can pass a full URL, a path, or just the form name. The CLI resolves it using `baseUrl` and `skjemaUrl` from config:
75
76
  ```
76
- form-tester test <full-url> --auto --pnr <pnr> --persona <id> --scenario "<text>"
77
+ form-tester test SLV-PasRapp-2020 --auto # just form name
78
+ form-tester test skjemautfyller/SLV-PasRapp-2020 --auto # path
79
+ form-tester test https://example.com/skjemautfyller/X --auto # full URL
77
80
  ```
81
+ To check resolution: `form-tester url SLV-PasRapp-2020`
78
82
 
79
83
  Step 2 — Dismiss cookies:
80
84
  ```
@@ -16,13 +16,17 @@ npm install -g form-tester
16
16
  form-tester install
17
17
  form-tester install --global # or install to ~/.claude/skills/
18
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"
19
+ # Non-interactive mode accepts form name, path, or full URL:
20
+ form-tester test SLV-PasRapp-2020 --auto
21
+ form-tester test SLV-PasRapp-2020 --auto --pnr 12345 --persona ung-mann
22
+ form-tester test https://example.com/skjemautfyller/FORM --auto
22
23
 
23
24
  # Human mode (user picks persona and scenario):
24
- form-tester test <url> --human # lists personas, ask user
25
- form-tester test <url> --human --persona ung-mann --scenario "test X" # run with user's choices
25
+ form-tester test SLV-PasRapp-2020 --human # lists personas
26
+ form-tester test SLV-PasRapp-2020 --human --persona ung-mann --scenario "X" # with choices
27
+
28
+ # Check URL resolution:
29
+ form-tester url SLV-PasRapp-2020
26
30
 
27
31
  # Full interactive CLI:
28
32
  form-tester
@@ -8,6 +8,7 @@ User must install globally first:
8
8
  ```bash
9
9
  npm install -g form-tester
10
10
  form-tester install
11
+ form-tester init # set baseUrl, pnr, person, etc.
11
12
  ```
12
13
 
13
14
  ## Running a test
@@ -16,16 +17,15 @@ When the user gives you a form URL to test, execute ALL steps below in sequence
16
17
 
17
18
  ### Step 1 — Start the test
18
19
 
19
- If the user gives a partial URL (e.g. `skjemautfyller/SLV-PasRapp-2020`), read `form-tester.config.json` first to get `baseUrl` and `pnr`. Construct the full URL as `{baseUrl}/{partial-path}?pnr={pnr}`. Do NOT guess the domain — always use `baseUrl` from config.
20
-
21
- ```bash
22
- form-tester test <full-url> --auto
23
- ```
24
- Or with options:
20
+ You can pass a full URL, a path, or just the form name. The CLI resolves it using `baseUrl` and `skjemaUrl` from config:
25
21
  ```bash
26
- form-tester test <full-url> --auto --pnr 12345 --persona ung-mann --scenario "test validation"
22
+ form-tester test SLV-PasRapp-2020 --auto # just form name
23
+ form-tester test skjemautfyller/SLV-PasRapp-2020 --auto # path
24
+ form-tester test https://example.com/skjemautfyller/X --auto # full URL
27
25
  ```
28
26
 
27
+ To check how a form name resolves: `form-tester url SLV-PasRapp-2020`
28
+
29
29
  ### Step 2 — Dismiss cookies
30
30
  ```bash
31
31
  form-tester cookies
@@ -1,5 +1,7 @@
1
1
  {
2
2
  "pnr": "YOUR_PNR_HERE",
3
3
  "person": "",
4
- "baseUrl": ""
4
+ "baseUrl": "",
5
+ "skjemaUrl": "/skjemautfyller",
6
+ "dokumenterUrlTemplate": "/dokumenter?pnr={PNR}"
5
7
  }
package/form-tester.js CHANGED
@@ -7,7 +7,7 @@ const { spawn, execSync } = require("child_process");
7
7
  const CONFIG_PATH = path.join(process.cwd(), "form-tester.config.json");
8
8
  const OUTPUT_BASE = path.resolve(process.cwd(), "output");
9
9
  const ISSUES_PATH = path.join(OUTPUT_BASE, "issues.jsonl");
10
- const LOCAL_VERSION = "0.10.3";
10
+ const LOCAL_VERSION = "0.11.1";
11
11
  const RECOMMENDED_PERSON = "Uromantisk Direktør";
12
12
 
13
13
  // Recording — persisted to disk so `form-tester exec` can append across processes
@@ -659,6 +659,7 @@ const DEFAULT_CONFIG = {
659
659
  pnr: "",
660
660
  person: "",
661
661
  baseUrl: "",
662
+ skjemaUrl: "/skjemautfyller",
662
663
  dokumenterUrlTemplate: "/dokumenter?pnr={PNR}",
663
664
  lastTestUrl: "",
664
665
  lastRunDir: "",
@@ -694,6 +695,20 @@ function resolveDokumenterUrl(config) {
694
695
  return url;
695
696
  }
696
697
 
698
+ function resolveFormUrl(input, config) {
699
+ // If it's already a full URL, return as-is
700
+ if (input.startsWith("http://") || input.startsWith("https://")) return input;
701
+ const base = config.baseUrl || "";
702
+ // If it's a path like /skjemautfyller/FORM-ID or skjemautfyller/FORM-ID
703
+ if (input.includes("/")) {
704
+ const path = input.startsWith("/") ? input : `/${input}`;
705
+ return `${base}${path}`;
706
+ }
707
+ // It's just a form name like SLV-PasRapp-2020
708
+ const skjema = config.skjemaUrl || "/skjemautfyller";
709
+ return `${base}${skjema}/${input}`;
710
+ }
711
+
697
712
  function extractPnrFromUrl(url) {
698
713
  try {
699
714
  const parsed = new URL(url);
@@ -921,9 +936,11 @@ function printHelp() {
921
936
  [
922
937
  "",
923
938
  "Subcommands (run directly):",
939
+ " form-tester init Set up config (baseUrl, pnr, person, etc.)",
924
940
  " form-tester install [--global] Install skill files into project or ~/.claude/skills/",
925
- " form-tester test <url> --auto Non-interactive test (for AI agents)",
926
- " form-tester test <url> --human Interactive test with prompts",
941
+ " form-tester test <name-or-url> --auto Non-interactive test (for AI agents)",
942
+ " form-tester test <name-or-url> --human Interactive test with prompts",
943
+ " form-tester url <name-or-path> Resolve form name/path to full URL",
927
944
  " form-tester exec <command> [args] Run playwright-cli command (recorded)",
928
945
  " form-tester replay <recording.json> Replay a recorded test run",
929
946
  " form-tester cookies Dismiss cookie banner",
@@ -1720,6 +1737,51 @@ function install(targetDir, isGlobal) {
1720
1737
  async function main() {
1721
1738
  const args = process.argv.slice(2);
1722
1739
 
1740
+ if (args[0] === "init") {
1741
+ const config = loadConfig();
1742
+ console.log("Form Tester Setup\n");
1743
+ console.log("Current config:");
1744
+ console.log(` baseUrl: ${config.baseUrl || "(not set)"}`);
1745
+ console.log(` pnr: ${config.pnr || "(not set)"}`);
1746
+ console.log(` person: ${config.person || "(not set)"}`);
1747
+ console.log(` skjemaUrl: ${config.skjemaUrl || "/skjemautfyller"}`);
1748
+ console.log(` dokumenterUrl: ${config.dokumenterUrlTemplate || "/dokumenter?pnr={PNR}"}`);
1749
+ console.log("");
1750
+
1751
+ const currentRl = ensureReadline();
1752
+
1753
+ const prompt = (question, current) => new Promise((resolve) => {
1754
+ const suffix = current ? ` [${current}]` : "";
1755
+ currentRl.question(`${question}${suffix}: `, (answer) => {
1756
+ resolve(answer.trim() || current || "");
1757
+ });
1758
+ });
1759
+
1760
+ config.baseUrl = await prompt("Base URL (e.g. https://tjenester-a-vak-sprak.int-hn.nhn.no)", config.baseUrl);
1761
+ config.pnr = await prompt("PNR (fødselsnummer for test)", config.pnr);
1762
+ config.person = await prompt("Default person name (e.g. Uromantisk Direktør)", config.person);
1763
+ config.skjemaUrl = await prompt("Skjema path prefix", config.skjemaUrl || "/skjemautfyller");
1764
+ config.dokumenterUrlTemplate = await prompt("Dokumenter URL template", config.dokumenterUrlTemplate || "/dokumenter?pnr={PNR}");
1765
+
1766
+ saveConfig(config);
1767
+ currentRl.close();
1768
+
1769
+ console.log("\nConfig saved to form-tester.config.json:");
1770
+ console.log(` baseUrl: ${config.baseUrl}`);
1771
+ console.log(` pnr: ${config.pnr}`);
1772
+ console.log(` person: ${config.person}`);
1773
+ console.log(` skjemaUrl: ${config.skjemaUrl}`);
1774
+ console.log(` dokumenterUrl: ${config.dokumenterUrlTemplate}`);
1775
+
1776
+ // Test URL resolution
1777
+ console.log(`\nTest: form-tester test SLV-PasRapp-2020 --auto`);
1778
+ const testUrl = resolveFormUrl("SLV-PasRapp-2020", config);
1779
+ const withPnr = config.pnr && !extractPnrFromUrl(testUrl) ? setPnrOnUrl(testUrl, config.pnr) : testUrl;
1780
+ console.log(` → ${withPnr}`);
1781
+
1782
+ process.exit(0);
1783
+ }
1784
+
1723
1785
  if (args[0] === "install") {
1724
1786
  const isGlobal = args.includes("--global") || args.includes("-g");
1725
1787
  const remaining = args.slice(1).filter((a) => a !== "--global" && a !== "-g");
@@ -1824,6 +1886,34 @@ async function main() {
1824
1886
  process.exit(code);
1825
1887
  }
1826
1888
 
1889
+ if (args[0] === "url") {
1890
+ const config = loadConfig();
1891
+ const input = args.slice(1).join(" ");
1892
+ if (!input) {
1893
+ console.error("Usage: form-tester url <form-name-or-path>");
1894
+ console.error("\nExamples:");
1895
+ console.error(" form-tester url SLV-PasRapp-2020");
1896
+ console.error(" form-tester url skjemautfyller/SLV-PasRapp-2020");
1897
+ console.error(" form-tester url https://example.com/skjemautfyller/FORM");
1898
+ console.error(`\nConfig: baseUrl=${config.baseUrl || "(not set)"}, skjemaUrl=${config.skjemaUrl || "/skjemautfyller"}, pnr=${config.pnr || "(not set)"}`);
1899
+ console.error("\nRun 'form-tester init' to configure.");
1900
+ process.exit(1);
1901
+ }
1902
+ let formUrl = resolveFormUrl(input, config);
1903
+ if (config.pnr && !extractPnrFromUrl(formUrl)) {
1904
+ formUrl = setPnrOnUrl(formUrl, config.pnr);
1905
+ }
1906
+ // Also resolve dokumenter URL
1907
+ const tmpConfig = { ...config, lastTestUrl: formUrl };
1908
+ const dokUrl = resolveDokumenterUrl(tmpConfig);
1909
+
1910
+ console.log(`Form URL: ${formUrl}`);
1911
+ console.log(`Dokumenter URL: ${dokUrl || "(not available — set pnr)"}`);
1912
+ console.log(`Person: ${config.person || "(not set)"}`);
1913
+ console.log(`\nRun: form-tester test ${input} --auto`);
1914
+ process.exit(0);
1915
+ }
1916
+
1827
1917
  if (args[0] === "cookies") {
1828
1918
  const code = await handleCookies();
1829
1919
  process.exit(code);
@@ -1844,12 +1934,13 @@ async function main() {
1844
1934
 
1845
1935
  if (args[0] === "test" && args.includes("--human")) {
1846
1936
  const config = loadConfig();
1847
- const url = args.find((a) => a.startsWith("http"));
1937
+ const flagVal = (flag) => args.includes(flag) ? args[args.indexOf(flag) + 1] : undefined;
1938
+ const rawUrl = args.find((a) => a !== "test" && !a.startsWith("--") && a !== flagVal("--persona") && a !== flagVal("--scenario") && a !== flagVal("--pnr"));
1939
+ const url = rawUrl ? resolveFormUrl(rawUrl, config) : null;
1848
1940
  if (!url) {
1849
- console.error("Usage: form-tester test <url> --human --persona <id> --scenario \"<text>\"");
1941
+ console.error("Usage: form-tester test <form-name-or-url> --human --persona <id> --scenario \"<text>\"");
1850
1942
  process.exit(1);
1851
1943
  }
1852
- const flagVal = (flag) => args.includes(flag) ? args[args.indexOf(flag) + 1] : undefined;
1853
1944
  const personaFlag = flagVal("--persona");
1854
1945
  const scenarioFlag = flagVal("--scenario");
1855
1946
 
@@ -1876,12 +1967,13 @@ async function main() {
1876
1967
 
1877
1968
  if (args[0] === "test" && args.includes("--auto")) {
1878
1969
  const config = loadConfig();
1879
- const url = args.find((a) => a.startsWith("http"));
1970
+ const flagVal = (flag) => args.includes(flag) ? args[args.indexOf(flag) + 1] : undefined;
1971
+ const rawUrl = args.find((a) => a !== "test" && !a.startsWith("--") && a !== flagVal("--persona") && a !== flagVal("--scenario") && a !== flagVal("--pnr"));
1972
+ const url = rawUrl ? resolveFormUrl(rawUrl, config) : null;
1880
1973
  if (!url) {
1881
- console.error("Usage: form-tester test <url> --auto [--pnr <pnr>] [--persona <id>] [--scenario <text>] [--silent|--verbose]");
1974
+ console.error("Usage: form-tester test <form-name-or-url> --auto [--pnr <pnr>] [--persona <id>] [--scenario <text>] [--silent|--verbose]");
1882
1975
  process.exit(1);
1883
1976
  }
1884
- const flagVal = (flag) => args.includes(flag) ? args[args.indexOf(flag) + 1] : undefined;
1885
1977
  const verbosity = args.includes("--silent") ? "silent" : args.includes("--verbose") ? "verbose" : "normal";
1886
1978
  await handleTestAuto(url, config, {
1887
1979
  pnr: flagVal("--pnr"),
@@ -1941,6 +2033,7 @@ module.exports = {
1941
2033
  finalizeRecording,
1942
2034
  logIssue,
1943
2035
  listIssues,
2036
+ resolveFormUrl,
1944
2037
  ISSUE_CATEGORIES,
1945
2038
  };
1946
2039
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form-tester",
3
- "version": "0.10.3",
3
+ "version": "0.11.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": {