From b25c604af03c79dfa365c61d55223615235eec81 Mon Sep 17 00:00:00 2001 From: Joseph McCarron Date: Sat, 17 Jan 2026 05:38:22 +0000 Subject: [PATCH 1/4] backwards compatible, now with esm build and ts. tests still js. --- dist/files.d.ts | 16 + dist/files.d.ts.map | 1 + dist/files.js | 123 + dist/files.js.map | 1 + dist/index.d.ts | 5 + dist/index.d.ts.map | 1 + dist/index.js | 13 + dist/index.js.map | 1 + dist/index.mjs | 4 + dist/resolvePaths.d.ts | 28 + dist/resolvePaths.d.ts.map | 1 + dist/resolvePaths.js | 236 + dist/resolvePaths.js.map | 1 + dist/schemas/index.d.ts | 5 + dist/schemas/index.d.ts.map | 1 + dist/schemas/index.js | 9 + dist/schemas/index.js.map | 1 + dist/schemas/schemas.json | 121359 +++++++++++++++ dist/types/generated/checkLink_v3.d.ts | 27 + dist/types/generated/checkLink_v3.d.ts.map | 1 + dist/types/generated/checkLink_v3.js | 8 + dist/types/generated/checkLink_v3.js.map | 1 + dist/types/generated/click_v3.d.ts | 16 + dist/types/generated/click_v3.d.ts.map | 1 + dist/types/generated/click_v3.js | 8 + dist/types/generated/click_v3.js.map | 1 + dist/types/generated/config_v3.d.ts | 398 + dist/types/generated/config_v3.d.ts.map | 1 + dist/types/generated/config_v3.js | 8 + dist/types/generated/config_v3.js.map | 1 + dist/types/generated/context_v3.d.ts | 108 + dist/types/generated/context_v3.d.ts.map | 1 + dist/types/generated/context_v3.js | 8 + dist/types/generated/context_v3.js.map | 1 + dist/types/generated/dragAndDrop_v3.d.ts | 37 + dist/types/generated/dragAndDrop_v3.d.ts.map | 1 + dist/types/generated/dragAndDrop_v3.js | 8 + dist/types/generated/dragAndDrop_v3.js.map | 1 + dist/types/generated/endRecord_v3.d.ts | 9 + dist/types/generated/endRecord_v3.d.ts.map | 1 + dist/types/generated/endRecord_v3.js | 8 + dist/types/generated/endRecord_v3.js.map | 1 + dist/types/generated/find_v3.d.ts | 16 + dist/types/generated/find_v3.d.ts.map | 1 + dist/types/generated/find_v3.js | 8 + dist/types/generated/find_v3.js.map | 1 + dist/types/generated/goTo_v3.d.ts | 46 + dist/types/generated/goTo_v3.d.ts.map | 1 + dist/types/generated/goTo_v3.js | 8 + dist/types/generated/goTo_v3.js.map | 1 + dist/types/generated/httpRequest_v3.d.ts | 16 + dist/types/generated/httpRequest_v3.d.ts.map | 1 + dist/types/generated/httpRequest_v3.js | 8 + dist/types/generated/httpRequest_v3.js.map | 1 + dist/types/generated/loadCookie_v3.d.ts | 16 + dist/types/generated/loadCookie_v3.d.ts.map | 1 + dist/types/generated/loadCookie_v3.js | 8 + dist/types/generated/loadCookie_v3.js.map | 1 + dist/types/generated/loadVariables_v3.d.ts | 9 + .../types/generated/loadVariables_v3.d.ts.map | 1 + dist/types/generated/loadVariables_v3.js | 8 + dist/types/generated/loadVariables_v3.js.map | 1 + dist/types/generated/openApi_v3.d.ts | 62 + dist/types/generated/openApi_v3.d.ts.map | 1 + dist/types/generated/openApi_v3.js | 8 + dist/types/generated/openApi_v3.js.map | 1 + dist/types/generated/record_v3.d.ts | 32 + dist/types/generated/record_v3.d.ts.map | 1 + dist/types/generated/record_v3.js | 8 + dist/types/generated/record_v3.js.map | 1 + dist/types/generated/report_v3.d.ts | 174 + dist/types/generated/report_v3.d.ts.map | 1 + dist/types/generated/report_v3.js | 8 + dist/types/generated/report_v3.js.map | 1 + dist/types/generated/resolvedTests_v3.d.ts | 571 + .../types/generated/resolvedTests_v3.d.ts.map | 1 + dist/types/generated/resolvedTests_v3.js | 8 + dist/types/generated/resolvedTests_v3.js.map | 1 + dist/types/generated/runCode_v3.d.ts | 57 + dist/types/generated/runCode_v3.d.ts.map | 1 + dist/types/generated/runCode_v3.js | 8 + dist/types/generated/runCode_v3.js.map | 1 + dist/types/generated/runShell_v3.d.ts | 56 + dist/types/generated/runShell_v3.d.ts.map | 1 + dist/types/generated/runShell_v3.js | 8 + dist/types/generated/runShell_v3.js.map | 1 + dist/types/generated/saveCookie_v3.d.ts | 16 + dist/types/generated/saveCookie_v3.d.ts.map | 1 + dist/types/generated/saveCookie_v3.js | 8 + dist/types/generated/saveCookie_v3.js.map | 1 + dist/types/generated/screenshot_v3.d.ts | 74 + dist/types/generated/screenshot_v3.d.ts.map | 1 + dist/types/generated/screenshot_v3.js | 8 + dist/types/generated/screenshot_v3.js.map | 1 + .../types/generated/sourceIntegration_v3.d.ts | 30 + .../generated/sourceIntegration_v3.d.ts.map | 1 + dist/types/generated/sourceIntegration_v3.js | 8 + .../generated/sourceIntegration_v3.js.map | 1 + dist/types/generated/spec_v3.d.ts | 159 + dist/types/generated/spec_v3.d.ts.map | 1 + dist/types/generated/spec_v3.js | 8 + dist/types/generated/spec_v3.js.map | 1 + dist/types/generated/step_v3.d.ts | 1270 + dist/types/generated/step_v3.d.ts.map | 1 + dist/types/generated/step_v3.js | 8 + dist/types/generated/step_v3.js.map | 1 + dist/types/generated/stopRecord_v3.d.ts | 9 + dist/types/generated/stopRecord_v3.d.ts.map | 1 + dist/types/generated/stopRecord_v3.js | 8 + dist/types/generated/stopRecord_v3.js.map | 1 + dist/types/generated/test_v3.d.ts | 2915 + dist/types/generated/test_v3.d.ts.map | 1 + dist/types/generated/test_v3.js | 8 + dist/types/generated/test_v3.js.map | 1 + dist/types/generated/type_v3.d.ts | 54 + dist/types/generated/type_v3.d.ts.map | 1 + dist/types/generated/type_v3.js | 8 + dist/types/generated/type_v3.js.map | 1 + dist/types/generated/wait_v3.d.ts | 12 + dist/types/generated/wait_v3.d.ts.map | 1 + dist/types/generated/wait_v3.js | 8 + dist/types/generated/wait_v3.js.map | 1 + dist/validate.d.ts | 41 + dist/validate.d.ts.map | 1 + dist/validate.js | 542 + dist/validate.js.map | 1 + package-lock.json | 197 +- package.json | 19 +- plans/plan-typescriptMigration.prompt.md | 25 + scripts/createEsmWrapper.js | 21 + scripts/generateTypes.js | 45 + src/files.ts | 86 + src/index.ts | 4 + src/resolvePaths.ts | 233 + src/schemas/index.ts | 6 + src/types/generated/checkLink_v3.ts | 29 + src/types/generated/click_v3.ts | 17 + src/types/generated/config_v3.ts | 405 + src/types/generated/context_v3.ts | 112 + src/types/generated/dragAndDrop_v3.ts | 39 + src/types/generated/endRecord_v3.ts | 10 + src/types/generated/find_v3.ts | 17 + src/types/generated/goTo_v3.ts | 48 + src/types/generated/httpRequest_v3.ts | 17 + src/types/generated/loadCookie_v3.ts | 17 + src/types/generated/loadVariables_v3.ts | 10 + src/types/generated/openApi_v3.ts | 64 + src/types/generated/record_v3.ts | 34 + src/types/generated/report_v3.ts | 183 + src/types/generated/resolvedTests_v3.ts | 585 + src/types/generated/runCode_v3.ts | 59 + src/types/generated/runShell_v3.ts | 58 + src/types/generated/saveCookie_v3.ts | 17 + src/types/generated/screenshot_v3.ts | 76 + src/types/generated/sourceIntegration_v3.ts | 31 + src/types/generated/spec_v3.ts | 166 + src/types/generated/step_v3.ts | 1288 + src/types/generated/stopRecord_v3.ts | 10 + src/types/generated/test_v3.ts | 3048 + src/types/generated/type_v3.ts | 56 + src/types/generated/wait_v3.ts | 13 + src/validate.ts | 605 + test/files.test.js | 2 +- test/resolvePaths.test.js | 2 +- test/schema.test.js | 2 +- test/validate.test.js | 2 +- tsconfig.json | 22 + 167 files changed, 136512 insertions(+), 8 deletions(-) create mode 100644 dist/files.d.ts create mode 100644 dist/files.d.ts.map create mode 100644 dist/files.js create mode 100644 dist/files.js.map create mode 100644 dist/index.d.ts create mode 100644 dist/index.d.ts.map create mode 100644 dist/index.js create mode 100644 dist/index.js.map create mode 100644 dist/index.mjs create mode 100644 dist/resolvePaths.d.ts create mode 100644 dist/resolvePaths.d.ts.map create mode 100644 dist/resolvePaths.js create mode 100644 dist/resolvePaths.js.map create mode 100644 dist/schemas/index.d.ts create mode 100644 dist/schemas/index.d.ts.map create mode 100644 dist/schemas/index.js create mode 100644 dist/schemas/index.js.map create mode 100644 dist/schemas/schemas.json create mode 100644 dist/types/generated/checkLink_v3.d.ts create mode 100644 dist/types/generated/checkLink_v3.d.ts.map create mode 100644 dist/types/generated/checkLink_v3.js create mode 100644 dist/types/generated/checkLink_v3.js.map create mode 100644 dist/types/generated/click_v3.d.ts create mode 100644 dist/types/generated/click_v3.d.ts.map create mode 100644 dist/types/generated/click_v3.js create mode 100644 dist/types/generated/click_v3.js.map create mode 100644 dist/types/generated/config_v3.d.ts create mode 100644 dist/types/generated/config_v3.d.ts.map create mode 100644 dist/types/generated/config_v3.js create mode 100644 dist/types/generated/config_v3.js.map create mode 100644 dist/types/generated/context_v3.d.ts create mode 100644 dist/types/generated/context_v3.d.ts.map create mode 100644 dist/types/generated/context_v3.js create mode 100644 dist/types/generated/context_v3.js.map create mode 100644 dist/types/generated/dragAndDrop_v3.d.ts create mode 100644 dist/types/generated/dragAndDrop_v3.d.ts.map create mode 100644 dist/types/generated/dragAndDrop_v3.js create mode 100644 dist/types/generated/dragAndDrop_v3.js.map create mode 100644 dist/types/generated/endRecord_v3.d.ts create mode 100644 dist/types/generated/endRecord_v3.d.ts.map create mode 100644 dist/types/generated/endRecord_v3.js create mode 100644 dist/types/generated/endRecord_v3.js.map create mode 100644 dist/types/generated/find_v3.d.ts create mode 100644 dist/types/generated/find_v3.d.ts.map create mode 100644 dist/types/generated/find_v3.js create mode 100644 dist/types/generated/find_v3.js.map create mode 100644 dist/types/generated/goTo_v3.d.ts create mode 100644 dist/types/generated/goTo_v3.d.ts.map create mode 100644 dist/types/generated/goTo_v3.js create mode 100644 dist/types/generated/goTo_v3.js.map create mode 100644 dist/types/generated/httpRequest_v3.d.ts create mode 100644 dist/types/generated/httpRequest_v3.d.ts.map create mode 100644 dist/types/generated/httpRequest_v3.js create mode 100644 dist/types/generated/httpRequest_v3.js.map create mode 100644 dist/types/generated/loadCookie_v3.d.ts create mode 100644 dist/types/generated/loadCookie_v3.d.ts.map create mode 100644 dist/types/generated/loadCookie_v3.js create mode 100644 dist/types/generated/loadCookie_v3.js.map create mode 100644 dist/types/generated/loadVariables_v3.d.ts create mode 100644 dist/types/generated/loadVariables_v3.d.ts.map create mode 100644 dist/types/generated/loadVariables_v3.js create mode 100644 dist/types/generated/loadVariables_v3.js.map create mode 100644 dist/types/generated/openApi_v3.d.ts create mode 100644 dist/types/generated/openApi_v3.d.ts.map create mode 100644 dist/types/generated/openApi_v3.js create mode 100644 dist/types/generated/openApi_v3.js.map create mode 100644 dist/types/generated/record_v3.d.ts create mode 100644 dist/types/generated/record_v3.d.ts.map create mode 100644 dist/types/generated/record_v3.js create mode 100644 dist/types/generated/record_v3.js.map create mode 100644 dist/types/generated/report_v3.d.ts create mode 100644 dist/types/generated/report_v3.d.ts.map create mode 100644 dist/types/generated/report_v3.js create mode 100644 dist/types/generated/report_v3.js.map create mode 100644 dist/types/generated/resolvedTests_v3.d.ts create mode 100644 dist/types/generated/resolvedTests_v3.d.ts.map create mode 100644 dist/types/generated/resolvedTests_v3.js create mode 100644 dist/types/generated/resolvedTests_v3.js.map create mode 100644 dist/types/generated/runCode_v3.d.ts create mode 100644 dist/types/generated/runCode_v3.d.ts.map create mode 100644 dist/types/generated/runCode_v3.js create mode 100644 dist/types/generated/runCode_v3.js.map create mode 100644 dist/types/generated/runShell_v3.d.ts create mode 100644 dist/types/generated/runShell_v3.d.ts.map create mode 100644 dist/types/generated/runShell_v3.js create mode 100644 dist/types/generated/runShell_v3.js.map create mode 100644 dist/types/generated/saveCookie_v3.d.ts create mode 100644 dist/types/generated/saveCookie_v3.d.ts.map create mode 100644 dist/types/generated/saveCookie_v3.js create mode 100644 dist/types/generated/saveCookie_v3.js.map create mode 100644 dist/types/generated/screenshot_v3.d.ts create mode 100644 dist/types/generated/screenshot_v3.d.ts.map create mode 100644 dist/types/generated/screenshot_v3.js create mode 100644 dist/types/generated/screenshot_v3.js.map create mode 100644 dist/types/generated/sourceIntegration_v3.d.ts create mode 100644 dist/types/generated/sourceIntegration_v3.d.ts.map create mode 100644 dist/types/generated/sourceIntegration_v3.js create mode 100644 dist/types/generated/sourceIntegration_v3.js.map create mode 100644 dist/types/generated/spec_v3.d.ts create mode 100644 dist/types/generated/spec_v3.d.ts.map create mode 100644 dist/types/generated/spec_v3.js create mode 100644 dist/types/generated/spec_v3.js.map create mode 100644 dist/types/generated/step_v3.d.ts create mode 100644 dist/types/generated/step_v3.d.ts.map create mode 100644 dist/types/generated/step_v3.js create mode 100644 dist/types/generated/step_v3.js.map create mode 100644 dist/types/generated/stopRecord_v3.d.ts create mode 100644 dist/types/generated/stopRecord_v3.d.ts.map create mode 100644 dist/types/generated/stopRecord_v3.js create mode 100644 dist/types/generated/stopRecord_v3.js.map create mode 100644 dist/types/generated/test_v3.d.ts create mode 100644 dist/types/generated/test_v3.d.ts.map create mode 100644 dist/types/generated/test_v3.js create mode 100644 dist/types/generated/test_v3.js.map create mode 100644 dist/types/generated/type_v3.d.ts create mode 100644 dist/types/generated/type_v3.d.ts.map create mode 100644 dist/types/generated/type_v3.js create mode 100644 dist/types/generated/type_v3.js.map create mode 100644 dist/types/generated/wait_v3.d.ts create mode 100644 dist/types/generated/wait_v3.d.ts.map create mode 100644 dist/types/generated/wait_v3.js create mode 100644 dist/types/generated/wait_v3.js.map create mode 100644 dist/validate.d.ts create mode 100644 dist/validate.d.ts.map create mode 100644 dist/validate.js create mode 100644 dist/validate.js.map create mode 100644 plans/plan-typescriptMigration.prompt.md create mode 100644 scripts/createEsmWrapper.js create mode 100644 scripts/generateTypes.js create mode 100644 src/files.ts create mode 100644 src/index.ts create mode 100644 src/resolvePaths.ts create mode 100644 src/schemas/index.ts create mode 100644 src/types/generated/checkLink_v3.ts create mode 100644 src/types/generated/click_v3.ts create mode 100644 src/types/generated/config_v3.ts create mode 100644 src/types/generated/context_v3.ts create mode 100644 src/types/generated/dragAndDrop_v3.ts create mode 100644 src/types/generated/endRecord_v3.ts create mode 100644 src/types/generated/find_v3.ts create mode 100644 src/types/generated/goTo_v3.ts create mode 100644 src/types/generated/httpRequest_v3.ts create mode 100644 src/types/generated/loadCookie_v3.ts create mode 100644 src/types/generated/loadVariables_v3.ts create mode 100644 src/types/generated/openApi_v3.ts create mode 100644 src/types/generated/record_v3.ts create mode 100644 src/types/generated/report_v3.ts create mode 100644 src/types/generated/resolvedTests_v3.ts create mode 100644 src/types/generated/runCode_v3.ts create mode 100644 src/types/generated/runShell_v3.ts create mode 100644 src/types/generated/saveCookie_v3.ts create mode 100644 src/types/generated/screenshot_v3.ts create mode 100644 src/types/generated/sourceIntegration_v3.ts create mode 100644 src/types/generated/spec_v3.ts create mode 100644 src/types/generated/step_v3.ts create mode 100644 src/types/generated/stopRecord_v3.ts create mode 100644 src/types/generated/test_v3.ts create mode 100644 src/types/generated/type_v3.ts create mode 100644 src/types/generated/wait_v3.ts create mode 100644 src/validate.ts create mode 100644 tsconfig.json diff --git a/dist/files.d.ts b/dist/files.d.ts new file mode 100644 index 00000000..65256b0f --- /dev/null +++ b/dist/files.d.ts @@ -0,0 +1,16 @@ +export interface ReadFileOptions { + fileURLOrPath: string; +} +/** + * Reads and parses content from a remote URL or local file path, supporting JSON and YAML formats. + * + * Attempts to parse the file content as JSON first, then YAML. If both parsing attempts fail, returns the raw content as a string. Returns `null` if the file cannot be read. + * + * @param options - Options object + * @param options.fileURLOrPath - The URL or local file path to read. + * @returns Parsed object for JSON or YAML files, raw string for other formats, or `null` if reading fails. + * + * @throws {Error} If {@link fileURLOrPath} is missing, not a string, or is an empty string. + */ +export declare function readFile({ fileURLOrPath }: ReadFileOptions): Promise; +//# sourceMappingURL=files.d.ts.map \ No newline at end of file diff --git a/dist/files.d.ts.map b/dist/files.d.ts.map new file mode 100644 index 00000000..1b813fb3 --- /dev/null +++ b/dist/files.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAAC,EAAE,aAAa,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC,CAiEnG"} \ No newline at end of file diff --git a/dist/files.js b/dist/files.js new file mode 100644 index 00000000..929498c4 --- /dev/null +++ b/dist/files.js @@ -0,0 +1,123 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.readFile = readFile; +const fs = __importStar(require("fs")); +const YAML = __importStar(require("yaml")); +const axios_1 = __importDefault(require("axios")); +const url_1 = require("url"); +/** + * Reads and parses content from a remote URL or local file path, supporting JSON and YAML formats. + * + * Attempts to parse the file content as JSON first, then YAML. If both parsing attempts fail, returns the raw content as a string. Returns `null` if the file cannot be read. + * + * @param options - Options object + * @param options.fileURLOrPath - The URL or local file path to read. + * @returns Parsed object for JSON or YAML files, raw string for other formats, or `null` if reading fails. + * + * @throws {Error} If {@link fileURLOrPath} is missing, not a string, or is an empty string. + */ +async function readFile({ fileURLOrPath }) { + if (!fileURLOrPath) { + throw new Error("fileURLOrPath is required"); + } + if (typeof fileURLOrPath !== "string") { + throw new Error("fileURLOrPath must be a string"); + } + if (fileURLOrPath.trim() === "") { + throw new Error("fileURLOrPath cannot be an empty string"); + } + let content; + let isRemote = false; + try { + const parsedURL = new url_1.URL(fileURLOrPath); + isRemote = + parsedURL.protocol === "http:" || parsedURL.protocol === "https:"; + } + catch (error) { + // Not a valid URL, assume local file path + } + if (isRemote) { + try { + const response = await axios_1.default.get(fileURLOrPath); + content = response.data; + } + catch (error) { + console.warn(`Error reading remote file from ${fileURLOrPath}: ${error.message}`); + return null; + } + } + else { + try { + content = await fs.promises.readFile(fileURLOrPath, "utf8"); + } + catch (error) { + if (error.code === "ENOENT") { + console.warn(`File not found: ${fileURLOrPath}`); + } + else { + console.warn(`Error reading file: ${error.message}`); + } + return null; + } + } + // Parse based on file extension + const ext = fileURLOrPath.split('.').pop()?.toLowerCase(); + if (ext === "json") { + try { + return JSON.parse(content); + } + catch (error) { + console.warn(`Failed to parse JSON: ${error.message}`); + return content; + } + } + else if (ext === "yaml" || ext === "yml") { + try { + return YAML.parse(content); + } + catch (error) { + console.warn(`Failed to parse YAML: ${error.message}`); + return content; + } + } + else { + return content; + } +} +//# sourceMappingURL=files.js.map \ No newline at end of file diff --git a/dist/files.js.map b/dist/files.js.map new file mode 100644 index 00000000..2eb7bd33 --- /dev/null +++ b/dist/files.js.map @@ -0,0 +1 @@ +{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,4BAiEC;AArFD,uCAAyB;AACzB,2CAA6B;AAC7B,kDAA0B;AAC1B,6BAA0B;AAM1B;;;;;;;;;;GAUG;AACI,KAAK,UAAU,QAAQ,CAAC,EAAE,aAAa,EAAmB;IAC/D,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,OAAO,aAAa,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,OAAe,CAAC;IACpB,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,SAAG,CAAC,aAAa,CAAC,CAAC;QACzC,QAAQ;YACN,SAAS,CAAC,QAAQ,KAAK,OAAO,IAAI,SAAS,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0CAA0C;IAC5C,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAChD,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CACV,kCAAkC,aAAa,KAAM,KAAe,CAAC,OAAO,EAAE,CAC/E,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,OAAO,CAAC,IAAI,CAAC,mBAAmB,aAAa,EAAE,CAAC,CAAC;YACnD,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,uBAAwB,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;IAE1D,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,yBAA0B,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YAClE,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;SAAM,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QAC3C,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,yBAA0B,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YAClE,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 00000000..c39e0fb3 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,5 @@ +export { schemas, SchemaKey, Schema } from "./schemas"; +export { validate, transformToSchemaKey, ValidateOptions, ValidateResult, TransformOptions } from "./validate"; +export { resolvePaths, ResolvePathsOptions } from "./resolvePaths"; +export { readFile, ReadFileOptions } from "./files"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map new file mode 100644 index 00000000..e6055ce4 --- /dev/null +++ b/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/G,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 00000000..7eabb7d6 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.readFile = exports.resolvePaths = exports.transformToSchemaKey = exports.validate = exports.schemas = void 0; +var schemas_1 = require("./schemas"); +Object.defineProperty(exports, "schemas", { enumerable: true, get: function () { return schemas_1.schemas; } }); +var validate_1 = require("./validate"); +Object.defineProperty(exports, "validate", { enumerable: true, get: function () { return validate_1.validate; } }); +Object.defineProperty(exports, "transformToSchemaKey", { enumerable: true, get: function () { return validate_1.transformToSchemaKey; } }); +var resolvePaths_1 = require("./resolvePaths"); +Object.defineProperty(exports, "resolvePaths", { enumerable: true, get: function () { return resolvePaths_1.resolvePaths; } }); +var files_1 = require("./files"); +Object.defineProperty(exports, "readFile", { enumerable: true, get: function () { return files_1.readFile; } }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 00000000..2a48b11e --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAAuD;AAA9C,kGAAA,OAAO,OAAA;AAChB,uCAA+G;AAAtG,oGAAA,QAAQ,OAAA;AAAE,gHAAA,oBAAoB,OAAA;AACvC,+CAAmE;AAA1D,4GAAA,YAAY,OAAA;AACrB,iCAAoD;AAA3C,iGAAA,QAAQ,OAAA"} \ No newline at end of file diff --git a/dist/index.mjs b/dist/index.mjs new file mode 100644 index 00000000..d3b65c2b --- /dev/null +++ b/dist/index.mjs @@ -0,0 +1,4 @@ +// ESM wrapper for CommonJS output +import cjsModule from './index.js'; +export const { schemas, validate, transformToSchemaKey, resolvePaths, readFile } = cjsModule; +export default cjsModule; diff --git a/dist/resolvePaths.d.ts b/dist/resolvePaths.d.ts new file mode 100644 index 00000000..0c565fc7 --- /dev/null +++ b/dist/resolvePaths.d.ts @@ -0,0 +1,28 @@ +type RelativePathBase = "file" | "cwd"; +type ObjectType = "config" | "spec"; +export interface ResolvePathsOptions { + config: { + relativePathBase: RelativePathBase; + }; + object: Record; + filePath: string; + nested?: boolean; + objectType?: ObjectType; +} +/** + * Convert recognized relative path properties in a config or spec object to absolute paths. + * + * Traverses the provided object (recursing into nested objects and arrays), resolving fields that represent filesystem paths according to the provided config.relativePathBase and reference filePath. On top-level calls the function infers whether the object is a config or spec via schema validation; for nested calls objectType must be provided. + * + * @param options - Options for path resolution. + * @param options.config - Configuration containing settings such as `relativePathBase`. + * @param options.object - The config or spec object whose path properties will be resolved. + * @param options.filePath - Reference file or directory used to resolve relative paths. + * @param options.nested - True when invoked recursively for nested objects. + * @param options.objectType - 'config' or 'spec'; required for nested invocations to select which properties to resolve. + * @returns The same object with applicable path properties converted to absolute paths. + * @throws {Error} If the top-level object matches neither config nor spec schema, or if `objectType` is missing for nested calls. + */ +export declare function resolvePaths({ config, object, filePath, nested, objectType, }: ResolvePathsOptions): Promise>; +export {}; +//# sourceMappingURL=resolvePaths.d.ts.map \ No newline at end of file diff --git a/dist/resolvePaths.d.ts.map b/dist/resolvePaths.d.ts.map new file mode 100644 index 00000000..487cb03b --- /dev/null +++ b/dist/resolvePaths.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"resolvePaths.d.ts","sourceRoot":"","sources":["../src/resolvePaths.ts"],"names":[],"mappings":"AAIA,KAAK,gBAAgB,GAAG,MAAM,GAAG,KAAK,CAAC;AACvC,KAAK,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE;QAAE,gBAAgB,EAAE,gBAAgB,CAAA;KAAE,CAAC;IAC/C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAAC,EACjC,MAAM,EACN,MAAM,EACN,QAAQ,EACR,MAAc,EACd,UAAU,GACX,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAqMpD"} \ No newline at end of file diff --git a/dist/resolvePaths.js b/dist/resolvePaths.js new file mode 100644 index 00000000..e7d62acb --- /dev/null +++ b/dist/resolvePaths.js @@ -0,0 +1,236 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.resolvePaths = resolvePaths; +const fs = __importStar(require("fs")); +const path = __importStar(require("path")); +const validate_1 = require("./validate"); +/** + * Convert recognized relative path properties in a config or spec object to absolute paths. + * + * Traverses the provided object (recursing into nested objects and arrays), resolving fields that represent filesystem paths according to the provided config.relativePathBase and reference filePath. On top-level calls the function infers whether the object is a config or spec via schema validation; for nested calls objectType must be provided. + * + * @param options - Options for path resolution. + * @param options.config - Configuration containing settings such as `relativePathBase`. + * @param options.object - The config or spec object whose path properties will be resolved. + * @param options.filePath - Reference file or directory used to resolve relative paths. + * @param options.nested - True when invoked recursively for nested objects. + * @param options.objectType - 'config' or 'spec'; required for nested invocations to select which properties to resolve. + * @returns The same object with applicable path properties converted to absolute paths. + * @throws {Error} If the top-level object matches neither config nor spec schema, or if `objectType` is missing for nested calls. + */ +async function resolvePaths({ config, object, filePath, nested = false, objectType, }) { + // Config properties that contain paths + const configPaths = [ + "input", + "output", + "loadVariables", + "setup", + "cleanup", + "configPath", + "beforeAny", + "afterAll", + "mediaDirectory", + "downloadDirectory", + "descriptionPath", + "path", + ]; + // Spec properties that contain paths + const specPaths = [ + "file", + "path", + "directory", + "before", + "after", + "loadVariables", + "setup", + "cleanup", + "savePath", + "saveDirectory", + "specPath", + "descriptionPath", + "workingDirectory", + ]; + // Spec objects that are configurable by the user and shouldn't be resolved + const specNoResolve = [ + "requestData", + "responseData", + "requestHeaders", + "responseHeaders", + "requestParams", + "responseParams", + ]; + /** + * Resolves a relative path to an absolute path using a specified base type and reference file path. + * + * @param baseType - Indicates whether to resolve relative to the reference file's directory ("file") or the current working directory ("cwd"). + * @param relativePath - The path to resolve, which may be relative or absolute. + * @param filePath - The reference file or directory path used for resolution. + * @returns The absolute path corresponding to {@link relativePath}. + * + * @remark If {@link relativePath} is already absolute, it is returned unchanged. If {@link filePath} does not exist, its extension is used to infer whether it is a file or directory. + * @remark HTTP and HTTPS URLs are returned unchanged without resolution. + */ + function resolve(baseType, relativePath, filePath) { + // If the path is an http:// or https:// URL, or a heretto: URI, return it + if (relativePath.startsWith("https://") || relativePath.startsWith("http://") || relativePath.startsWith("heretto:")) { + return relativePath; + } + // If path is already absolute, return it + if (path.isAbsolute(relativePath)) { + return relativePath; + } + // Check if filePath exists and is a file + const fileExists = fs.existsSync(filePath); + const isFile = fileExists + ? fs.lstatSync(filePath).isFile() + : path.parse(filePath).ext !== ""; + // Use directory of filePath if it's a file (or looks like one) + const basePath = isFile ? path.dirname(filePath) : filePath; + // Resolve the path based on the base type + return baseType === "file" + ? path.resolve(basePath, relativePath) + : path.resolve(relativePath); + } + const relativePathBase = config.relativePathBase; + let pathProperties; + if (!nested && !objectType) { + // Check if object matches the config schema + const validation = (0, validate_1.validate)({ + schemaKey: "config_v3", + object: { ...object }, + }); + if (validation.valid) { + pathProperties = configPaths; + objectType = "config"; + } + else { + // Check if object matches the spec schema + const validation = (0, validate_1.validate)({ + schemaKey: "spec_v3", + object: { ...object }, + }); + if (validation.valid) { + pathProperties = specPaths; + objectType = "spec"; + } + else { + throw new Error("Object isn't a valid config or spec."); + } + } + } + else if (nested && !objectType) { + // If the object is nested, the object type is required + throw new Error("Object type is required for nested objects."); + } + else if (objectType === "config") { + // If the object type is config, use configPaths + pathProperties = configPaths; + } + else if (objectType === "spec") { + // If the object type is spec, use specPaths + pathProperties = specPaths; + } + else { + throw new Error("Invalid objectType"); + } + // If the object is null or empty, return it as is + if (object === null || Object.keys(object).length === 0) { + return object; + } + for (const property of Object.keys(object)) { + // If the property is an array, recursively call resolvePaths for each item in the array + if (Array.isArray(object[property])) { + for (let i = 0; i < object[property].length; i++) { + const item = object[property][i]; + // If the item is an object, recursively call resolvePaths to resolve paths within the object + if (typeof item === "object") { + await resolvePaths({ + config: config, + object: item, + filePath: filePath, + nested: true, + objectType: objectType, + }); + } + else if (typeof item === "string" && + pathProperties.includes(property)) { + // Resolve the string path and write it back into the array + const resolved = property === "path" && + object.directory && + path.isAbsolute(object.directory) + ? resolve(relativePathBase, item, object.directory) + : resolve(relativePathBase, item, filePath); + object[property][i] = resolved; + } + } + } + // If the property is an object, recursively call resolvePaths to resolve paths within the object + else if (typeof object[property] === "object" && + ((objectType === "spec" && !specNoResolve.includes(property)) || + objectType === "config")) { + // If the property is an object, recursively call resolvePaths to resolve paths within the object + object[property] = await resolvePaths({ + config: config, + object: object[property], + filePath: filePath, + nested: true, + objectType: objectType, + }); + } + else if (typeof object[property] === "string") { + // If the property begins with "https://", "http://", or "heretto:", skip it + if (object[property].startsWith("https://") || + object[property].startsWith("http://") || + object[property].startsWith("heretto:")) { + continue; + } + // Check if it matches any of the path properties and resolve it if it does + if (pathProperties.includes(property)) { + if (property === "path" && object.directory) { + const directory = path.isAbsolute(object.directory) + ? object.directory + : resolve(relativePathBase, object.directory, filePath); + object[property] = resolve(relativePathBase, object[property], directory); + } + else { + object[property] = resolve(relativePathBase, object[property], filePath); + } + } + } + } + return object; +} +//# sourceMappingURL=resolvePaths.js.map \ No newline at end of file diff --git a/dist/resolvePaths.js.map b/dist/resolvePaths.js.map new file mode 100644 index 00000000..f4d23da2 --- /dev/null +++ b/dist/resolvePaths.js.map @@ -0,0 +1 @@ +{"version":3,"file":"resolvePaths.js","sourceRoot":"","sources":["../src/resolvePaths.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/schemas/index.d.ts b/dist/schemas/index.d.ts new file mode 100644 index 00000000..5e4e5e28 --- /dev/null +++ b/dist/schemas/index.d.ts @@ -0,0 +1,5 @@ +import schemasJson from "./schemas.json"; +export type SchemaKey = keyof typeof schemasJson; +export type Schema = (typeof schemasJson)[SchemaKey]; +export declare const schemas: typeof schemasJson; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/schemas/index.d.ts.map b/dist/schemas/index.d.ts.map new file mode 100644 index 00000000..5beddea0 --- /dev/null +++ b/dist/schemas/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,gBAAgB,CAAC;AAEzC,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAC;AACjD,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC;AAErD,eAAO,MAAM,OAAO,EAAE,OAAO,WAAyB,CAAC"} \ No newline at end of file diff --git a/dist/schemas/index.js b/dist/schemas/index.js new file mode 100644 index 00000000..c1f4fc05 --- /dev/null +++ b/dist/schemas/index.js @@ -0,0 +1,9 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.schemas = void 0; +const schemas_json_1 = __importDefault(require("./schemas.json")); +exports.schemas = schemas_json_1.default; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/schemas/index.js.map b/dist/schemas/index.js.map new file mode 100644 index 00000000..4ad52a28 --- /dev/null +++ b/dist/schemas/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":";;;;;;AAAA,kEAAyC;AAK5B,QAAA,OAAO,GAAuB,sBAAW,CAAC"} \ No newline at end of file diff --git a/dist/schemas/schemas.json b/dist/schemas/schemas.json new file mode 100644 index 00000000..c6c221b5 --- /dev/null +++ b/dist/schemas/schemas.json @@ -0,0 +1,121359 @@ +{ + "checkLink_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + }, + "click_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + "config_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "config", + "description": "Configuration options for Doc Detective operations.", + "type": "object", + "additionalProperties": false, + "dynamicDefaults": { + "configId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/config_v3.schema.json" + ] + }, + "configId": { + "description": "Identifier for the configuration.", + "type": "string" + }, + "configPath": { + "description": "Path to the configuration file.", + "type": "string", + "readOnly": true + }, + "input": { + "description": "Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.", + "default": ".", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "output": { + "description": "Path of the directory in which to store the output of Doc Detective commands. If a file path is specified, Doc Detective attempts to honor the file name specified, but file path behavior is controlled by the configured reporters.", + "type": "string", + "default": "." + }, + "recursive": { + "description": "If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specifications and source files.", + "type": "boolean", + "default": true + }, + "relativePathBase": { + "description": "Whether paths should be interpreted as relative to the current working directory (`cwd`) or to the file in which they're specified (`file`).", + "type": "string", + "enum": [ + "cwd", + "file" + ], + "default": "file" + }, + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + }, + "origin": { + "description": "Default protocol and domain to use for relative URLs.", + "type": "string" + }, + "beforeAny": { + "description": "Path(s) to test specifications to perform before those specified by `input`. Useful for setting up testing environments.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "afterAll": { + "description": "Path(s) to test specifications to perform after those specified by `input`. Useful for cleaning up testing environments.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "detectSteps": { + "type": "boolean", + "description": "Whether or not to detect steps in input files based on defined markup.", + "default": true + }, + "allowUnsafeSteps": { + "type": "boolean", + "description": "Whether or not to run potentially unsafe steps, such as those that might modify files or system state." + }, + "crawl": { + "description": "If `true`, crawls sitemap.xml files specified by URL to find additional files to test.", + "type": "boolean", + "default": false + }, + "processDitaMaps": { + "description": "If `true`, processes DITA maps and includes generated files as inputs.", + "type": "boolean", + "default": true + }, + "logLevel": { + "description": "Amount of detail to output when performing an operation.", + "type": "string", + "enum": [ + "silent", + "error", + "warning", + "info", + "debug" + ], + "default": "info" + }, + "runOn": { + "type": "array", + "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels.", + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + } + ] + } + }, + "fileTypes": { + "description": "Configuration for file types and their markup detection.", + "default": [ + "markdown", + "asciidoc", + "html", + "dita" + ], + "anyOf": [ + { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "$comment": "Simple mode: Reference predefined templates by name.", + "title": "File type (predefined)", + "type": "string", + "enum": [ + "markdown", + "asciidoc", + "html", + "dita" + ] + }, + { + "$comment": "Custom mode: Extend predefined templates or write whole new ones.", + "title": "File type (custom)", + "type": "object", + "anyOf": [ + { + "required": [ + "extensions" + ] + }, + { + "required": [ + "extends" + ] + } + ], + "properties": { + "name": { + "description": "Name of the file type.", + "type": "string" + }, + "extends": { + "description": "Base template to extend.", + "type": "string", + "enum": [ + "markdown", + "asciidoc", + "html" + ] + }, + "extensions": { + "description": "File extensions to use with type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "inlineStatements": { + "description": "Statements to include tests and steps inside the content of the file, such as within Markdown.", + "type": "object", + "properties": { + "testStart": { + "description": "Regular expressions that indicate the start of a test. If capture groups are used, the first capture group is used for the statement. If no capture groups are used, the entire match is used for the statement.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "testEnd": { + "description": "Regular expressions that indicate that the current test is complete.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "ignoreStart": { + "description": "Regular expressions that indicates that the following content should be ignored for testing purposes.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "ignoreEnd": { + "description": "Regular expressions that indicate that the ignored section of content is complete.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "step": { + "description": "Regular expressions that indicate a step in a test.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + } + }, + "title": "Inline statement definition" + }, + "markup": { + "description": "Markup definitions for the file type.", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "batchMatches": { + "description": "If `true`, all matches are combined into a single string.", + "type": "boolean", + "default": false + }, + "actions": { + "description": "Actions to perform when the markup type is detected.", + "anyOf": [ + { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + ] + } + } + ] + } + }, + "title": "Markup definition" + } + } + } + }, + { + "title": "File type (executable)", + "$comment": "Executable mode: Convert executable inputs directly into tests.", + "type": "object", + "required": [ + "extensions" + ], + "properties": { + "extensions": { + "description": "File extensions to use with type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "runShell": { + "description": "`runShell` step to perform for this file type. Use $1 as a placeholder for the file path.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + ] + } + } + } + ] + } + } + ] + }, + "integrations": { + "description": "Options for connecting to external services.", + "type": "object", + "additionalProperties": false, + "properties": { + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "docDetectiveApi": { + "type": "object", + "description": "Configuration for Doc Detective Orchestration API integration.", + "additionalProperties": false, + "properties": { + "apiKey": { + "type": "string", + "description": "API key for authenticating with the Doc Detective Orchestration API." + } + }, + "title": "Doc Detective Orchestration API" + }, + "heretto": { + "type": "array", + "description": "Configuration for Heretto CMS integrations. Each entry specifies a Heretto instance and a scenario to build and test.", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "organizationId", + "username", + "apiToken" + ], + "properties": { + "name": { + "type": "string", + "description": "Unique identifier for this Heretto integration. Used in logs and results." + }, + "organizationId": { + "type": "string", + "description": "The organization subdomain used to access Heretto CCMS (e.g., 'thunderbird' for thunderbird.heretto.com)." + }, + "username": { + "type": "string", + "description": "Heretto CCMS username (email address) for API authentication." + }, + "apiToken": { + "format": "password", + "minLength": 1, + "type": "string", + "description": "API token generated in Heretto CCMS for authentication. See https://help.heretto.com/en/heretto-ccms/api/ccms-api-authentication/basic-authentication#ariaid-title3" + }, + "scenarioName": { + "type": "string", + "description": "Name of the scenario to build and test.", + "default": "Doc Detective" + }, + "outputPath": { + "type": "string", + "description": "Local path where Heretto content was downloaded. Set automatically during processing.", + "readOnly": true + }, + "fileMapping": { + "type": "object", + "description": "Mapping of local file paths to Heretto file metadata. Set automatically during content loading.", + "readOnly": true, + "additionalProperties": { + "type": "object", + "properties": { + "fileId": { + "type": "string", + "description": "The UUID of the file in Heretto." + }, + "filePath": { + "type": "string", + "description": "The path of the file in Heretto." + } + } + } + }, + "uploadOnChange": { + "type": "boolean", + "description": "If `true`, uploads changed screenshots and other media files back to Heretto CMS after test execution.", + "default": false + }, + "resourceDependencies": { + "type": "object", + "description": "Mapping of Heretto file paths to their UUIDs and metadata. Set automatically during content loading by fetching ditamap resource dependencies.", + "readOnly": true, + "additionalProperties": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "description": "The UUID of the file in Heretto." + }, + "fullPath": { + "type": "string", + "description": "The full xmldb path of the file in Heretto." + }, + "name": { + "type": "string", + "description": "The file name." + }, + "parentFolderId": { + "type": "string", + "description": "The UUID of the parent folder in Heretto." + } + } + } + } + }, + "title": "Heretto CMS integration" + }, + "title": "Heretto CMS integrations" + } + }, + "title": "Integrations options" + }, + "telemetry": { + "description": "Options around sending telemetry for Doc Detective usage.", + "type": "object", + "additionalProperties": false, + "properties": { + "send": { + "description": "If `true`, sends Doc Detective telemetry.", + "type": "boolean", + "default": true + }, + "userId": { + "description": "Identifier for the organization, group, or individual running Doc Detective.", + "type": "string" + } + }, + "required": [ + "send" + ], + "default": { + "send": true + }, + "title": "Telemetry options" + }, + "concurrentRunners": { + "type": [ + "integer", + "boolean" + ], + "default": 1, + "minimum": 1, + "description": "Number of concurrent test runners. Set to true to use CPU core count (capped at 4).", + "not": { + "const": false + } + }, + "environment": { + "type": "object", + "description": "Environment information for the system running Doc Detective.", + "readOnly": true, + "additionalProperties": false, + "required": [ + "platform" + ], + "properties": { + "workingDirectory": { + "description": "The current working directory of the process running Doc Detective.", + "type": "string" + }, + "platform": { + "description": "The operating system type running Doc Detective.", + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "arch": { + "description": "The processor architecture of the system running Doc Detective.", + "type": "string", + "enum": [ + "arm32", + "arm64", + "x32", + "x64" + ] + } + }, + "title": "Environment details" + }, + "debug": { + "description": "Enable debugging mode. `true` allows pausing on breakpoints, waiting for user input before continuing. `stepThrough` pauses at every step, waiting for user input before continuing. `false` disables all debugging.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "enum": [ + "stepThrough" + ] + } + ], + "default": false + } + }, + "components": { + "schemas": { + "environment": { + "type": "object", + "description": "Environment information for the system running Doc Detective.", + "readOnly": true, + "additionalProperties": false, + "required": [ + "platform" + ], + "properties": { + "workingDirectory": { + "description": "The current working directory of the process running Doc Detective.", + "type": "string" + }, + "platform": { + "description": "The operating system type running Doc Detective.", + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "arch": { + "description": "The processor architecture of the system running Doc Detective.", + "type": "string", + "enum": [ + "arm32", + "arm64", + "x32", + "x64" + ] + } + }, + "title": "Environment details" + }, + "markupDefinition": { + "type": "object", + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "batchMatches": { + "description": "If `true`, all matches are combined into a single string.", + "type": "boolean", + "default": false + }, + "actions": { + "description": "Actions to perform when the markup type is detected.", + "anyOf": [ + { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + ] + } + } + ] + } + }, + "title": "Markup definition" + }, + "markupActionString": { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + "inlineStatements": { + "description": "Statements to include tests and steps inside the content of the file, such as within Markdown.", + "type": "object", + "properties": { + "testStart": { + "description": "Regular expressions that indicate the start of a test. If capture groups are used, the first capture group is used for the statement. If no capture groups are used, the entire match is used for the statement.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "testEnd": { + "description": "Regular expressions that indicate that the current test is complete.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "ignoreStart": { + "description": "Regular expressions that indicates that the following content should be ignored for testing purposes.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "ignoreEnd": { + "description": "Regular expressions that indicate that the ignored section of content is complete.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "step": { + "description": "Regular expressions that indicate a step in a test.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + } + }, + "title": "Inline statement definition" + }, + "stringOrArray": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + } + }, + "examples": [ + {}, + { + "input": ".", + "output": ".", + "recursive": true, + "loadVariables": ".env", + "fileTypes": [ + "markdown" + ] + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": [ + "md", + "markdown", + "mdx" + ], + "inlineStatements": { + "testStart": "", + "testEnd": "", + "ignoreStart": "", + "ignoreEnd": "", + "step": "" + }, + "markup": [ + { + "name": "onscreenText", + "regex": "\\*\\*.+?\\*\\*", + "actions": "find" + } + ] + } + ] + }, + { + "fileTypes": [ + { + "name": "Jupyter Notebooks", + "extensions": "ipynb", + "runShell": { + "command": "jupyter", + "args": [ + "nbconvert", + "--to", + "script", + "--execute", + "$1", + "--stdout" + ] + } + }, + { + "name": "JavaScript", + "extensions": "js", + "runShell": { + "command": "node $1" + } + }, + { + "name": "Python", + "extensions": "py", + "runShell": { + "command": "python $1" + } + } + ] + }, + { + "environment": { + "platform": "windows", + "arch": "x64" + } + }, + { + "concurrentRunners": 1 + }, + { + "concurrentRunners": true + }, + { + "concurrentRunners": 4 + }, + { + "debug": false + }, + { + "debug": true + }, + { + "debug": "stepThrough" + }, + { + "integrations": { + "docDetectiveApi": { + "apiKey": "your-api-key-here" + } + } + }, + { + "crawl": true + }, + { + "processDitaMaps": true + }, + { + "integrations": { + "heretto": [ + { + "name": "example", + "organizationId": "your-organization-id", + "username": "your-username", + "apiToken": "your-api-token" + } + ] + } + } + ] + }, + "context_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + }, + "dragAndDrop_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + }, + "find_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + }, + "goTo_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + }, + "loadCookie_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + }, + "loadVariables_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + }, + "httpRequest_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + }, + "openApi_v3": { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + "record_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + }, + "resolvedTests_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "resolvedTests", + "description": "A collection of resolved tests ready to be performed.", + "type": "object", + "dynamicDefaults": { + "resolvedTestsId": "uuid" + }, + "properties": { + "resolvedTestsId": { + "type": "string", + "description": "Unique identifier for the resolved tests." + }, + "config": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "config", + "description": "Configuration options for Doc Detective operations.", + "type": "object", + "additionalProperties": false, + "dynamicDefaults": { + "configId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/config_v3.schema.json" + ] + }, + "configId": { + "description": "Identifier for the configuration.", + "type": "string" + }, + "configPath": { + "description": "Path to the configuration file.", + "type": "string", + "readOnly": true + }, + "input": { + "description": "Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.", + "default": ".", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "output": { + "description": "Path of the directory in which to store the output of Doc Detective commands. If a file path is specified, Doc Detective attempts to honor the file name specified, but file path behavior is controlled by the configured reporters.", + "type": "string", + "default": "." + }, + "recursive": { + "description": "If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specifications and source files.", + "type": "boolean", + "default": true + }, + "relativePathBase": { + "description": "Whether paths should be interpreted as relative to the current working directory (`cwd`) or to the file in which they're specified (`file`).", + "type": "string", + "enum": [ + "cwd", + "file" + ], + "default": "file" + }, + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + }, + "origin": { + "description": "Default protocol and domain to use for relative URLs.", + "type": "string" + }, + "beforeAny": { + "description": "Path(s) to test specifications to perform before those specified by `input`. Useful for setting up testing environments.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "afterAll": { + "description": "Path(s) to test specifications to perform after those specified by `input`. Useful for cleaning up testing environments.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "detectSteps": { + "type": "boolean", + "description": "Whether or not to detect steps in input files based on defined markup.", + "default": true + }, + "allowUnsafeSteps": { + "type": "boolean", + "description": "Whether or not to run potentially unsafe steps, such as those that might modify files or system state." + }, + "crawl": { + "description": "If `true`, crawls sitemap.xml files specified by URL to find additional files to test.", + "type": "boolean", + "default": false + }, + "processDitaMaps": { + "description": "If `true`, processes DITA maps and includes generated files as inputs.", + "type": "boolean", + "default": true + }, + "logLevel": { + "description": "Amount of detail to output when performing an operation.", + "type": "string", + "enum": [ + "silent", + "error", + "warning", + "info", + "debug" + ], + "default": "info" + }, + "runOn": { + "type": "array", + "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels.", + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + } + ] + } + }, + "fileTypes": { + "description": "Configuration for file types and their markup detection.", + "default": [ + "markdown", + "asciidoc", + "html", + "dita" + ], + "anyOf": [ + { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "$comment": "Simple mode: Reference predefined templates by name.", + "title": "File type (predefined)", + "type": "string", + "enum": [ + "markdown", + "asciidoc", + "html", + "dita" + ] + }, + { + "$comment": "Custom mode: Extend predefined templates or write whole new ones.", + "title": "File type (custom)", + "type": "object", + "anyOf": [ + { + "required": [ + "extensions" + ] + }, + { + "required": [ + "extends" + ] + } + ], + "properties": { + "name": { + "description": "Name of the file type.", + "type": "string" + }, + "extends": { + "description": "Base template to extend.", + "type": "string", + "enum": [ + "markdown", + "asciidoc", + "html" + ] + }, + "extensions": { + "description": "File extensions to use with type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "inlineStatements": { + "description": "Statements to include tests and steps inside the content of the file, such as within Markdown.", + "type": "object", + "properties": { + "testStart": { + "description": "Regular expressions that indicate the start of a test. If capture groups are used, the first capture group is used for the statement. If no capture groups are used, the entire match is used for the statement.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "testEnd": { + "description": "Regular expressions that indicate that the current test is complete.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "ignoreStart": { + "description": "Regular expressions that indicates that the following content should be ignored for testing purposes.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "ignoreEnd": { + "description": "Regular expressions that indicate that the ignored section of content is complete.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "step": { + "description": "Regular expressions that indicate a step in a test.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + } + }, + "title": "Inline statement definition" + }, + "markup": { + "description": "Markup definitions for the file type.", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "batchMatches": { + "description": "If `true`, all matches are combined into a single string.", + "type": "boolean", + "default": false + }, + "actions": { + "description": "Actions to perform when the markup type is detected.", + "anyOf": [ + { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + ] + } + } + ] + } + }, + "title": "Markup definition" + } + } + } + }, + { + "title": "File type (executable)", + "$comment": "Executable mode: Convert executable inputs directly into tests.", + "type": "object", + "required": [ + "extensions" + ], + "properties": { + "extensions": { + "description": "File extensions to use with type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "runShell": { + "description": "`runShell` step to perform for this file type. Use $1 as a placeholder for the file path.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + ] + } + } + } + ] + } + } + ] + }, + "integrations": { + "description": "Options for connecting to external services.", + "type": "object", + "additionalProperties": false, + "properties": { + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "docDetectiveApi": { + "type": "object", + "description": "Configuration for Doc Detective Orchestration API integration.", + "additionalProperties": false, + "properties": { + "apiKey": { + "type": "string", + "description": "API key for authenticating with the Doc Detective Orchestration API." + } + }, + "title": "Doc Detective Orchestration API" + }, + "heretto": { + "type": "array", + "description": "Configuration for Heretto CMS integrations. Each entry specifies a Heretto instance and a scenario to build and test.", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "organizationId", + "username", + "apiToken" + ], + "properties": { + "name": { + "type": "string", + "description": "Unique identifier for this Heretto integration. Used in logs and results." + }, + "organizationId": { + "type": "string", + "description": "The organization subdomain used to access Heretto CCMS (e.g., 'thunderbird' for thunderbird.heretto.com)." + }, + "username": { + "type": "string", + "description": "Heretto CCMS username (email address) for API authentication." + }, + "apiToken": { + "format": "password", + "minLength": 1, + "type": "string", + "description": "API token generated in Heretto CCMS for authentication. See https://help.heretto.com/en/heretto-ccms/api/ccms-api-authentication/basic-authentication#ariaid-title3" + }, + "scenarioName": { + "type": "string", + "description": "Name of the scenario to build and test.", + "default": "Doc Detective" + }, + "outputPath": { + "type": "string", + "description": "Local path where Heretto content was downloaded. Set automatically during processing.", + "readOnly": true + }, + "fileMapping": { + "type": "object", + "description": "Mapping of local file paths to Heretto file metadata. Set automatically during content loading.", + "readOnly": true, + "additionalProperties": { + "type": "object", + "properties": { + "fileId": { + "type": "string", + "description": "The UUID of the file in Heretto." + }, + "filePath": { + "type": "string", + "description": "The path of the file in Heretto." + } + } + } + }, + "uploadOnChange": { + "type": "boolean", + "description": "If `true`, uploads changed screenshots and other media files back to Heretto CMS after test execution.", + "default": false + }, + "resourceDependencies": { + "type": "object", + "description": "Mapping of Heretto file paths to their UUIDs and metadata. Set automatically during content loading by fetching ditamap resource dependencies.", + "readOnly": true, + "additionalProperties": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "description": "The UUID of the file in Heretto." + }, + "fullPath": { + "type": "string", + "description": "The full xmldb path of the file in Heretto." + }, + "name": { + "type": "string", + "description": "The file name." + }, + "parentFolderId": { + "type": "string", + "description": "The UUID of the parent folder in Heretto." + } + } + } + } + }, + "title": "Heretto CMS integration" + }, + "title": "Heretto CMS integrations" + } + }, + "title": "Integrations options" + }, + "telemetry": { + "description": "Options around sending telemetry for Doc Detective usage.", + "type": "object", + "additionalProperties": false, + "properties": { + "send": { + "description": "If `true`, sends Doc Detective telemetry.", + "type": "boolean", + "default": true + }, + "userId": { + "description": "Identifier for the organization, group, or individual running Doc Detective.", + "type": "string" + } + }, + "required": [ + "send" + ], + "default": { + "send": true + }, + "title": "Telemetry options" + }, + "concurrentRunners": { + "type": [ + "integer", + "boolean" + ], + "default": 1, + "minimum": 1, + "description": "Number of concurrent test runners. Set to true to use CPU core count (capped at 4).", + "not": { + "const": false + } + }, + "environment": { + "type": "object", + "description": "Environment information for the system running Doc Detective.", + "readOnly": true, + "additionalProperties": false, + "required": [ + "platform" + ], + "properties": { + "workingDirectory": { + "description": "The current working directory of the process running Doc Detective.", + "type": "string" + }, + "platform": { + "description": "The operating system type running Doc Detective.", + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "arch": { + "description": "The processor architecture of the system running Doc Detective.", + "type": "string", + "enum": [ + "arm32", + "arm64", + "x32", + "x64" + ] + } + }, + "title": "Environment details" + }, + "debug": { + "description": "Enable debugging mode. `true` allows pausing on breakpoints, waiting for user input before continuing. `stepThrough` pauses at every step, waiting for user input before continuing. `false` disables all debugging.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "enum": [ + "stepThrough" + ] + } + ], + "default": false + } + }, + "components": { + "schemas": { + "environment": { + "type": "object", + "description": "Environment information for the system running Doc Detective.", + "readOnly": true, + "additionalProperties": false, + "required": [ + "platform" + ], + "properties": { + "workingDirectory": { + "description": "The current working directory of the process running Doc Detective.", + "type": "string" + }, + "platform": { + "description": "The operating system type running Doc Detective.", + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "arch": { + "description": "The processor architecture of the system running Doc Detective.", + "type": "string", + "enum": [ + "arm32", + "arm64", + "x32", + "x64" + ] + } + }, + "title": "Environment details" + }, + "markupDefinition": { + "type": "object", + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "batchMatches": { + "description": "If `true`, all matches are combined into a single string.", + "type": "boolean", + "default": false + }, + "actions": { + "description": "Actions to perform when the markup type is detected.", + "anyOf": [ + { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + ] + } + } + ] + } + }, + "title": "Markup definition" + }, + "markupActionString": { + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] + }, + "inlineStatements": { + "description": "Statements to include tests and steps inside the content of the file, such as within Markdown.", + "type": "object", + "properties": { + "testStart": { + "description": "Regular expressions that indicate the start of a test. If capture groups are used, the first capture group is used for the statement. If no capture groups are used, the entire match is used for the statement.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "testEnd": { + "description": "Regular expressions that indicate that the current test is complete.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "ignoreStart": { + "description": "Regular expressions that indicates that the following content should be ignored for testing purposes.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "ignoreEnd": { + "description": "Regular expressions that indicate that the ignored section of content is complete.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "step": { + "description": "Regular expressions that indicate a step in a test.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + } + }, + "title": "Inline statement definition" + }, + "stringOrArray": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + } + }, + "examples": [ + {}, + { + "input": ".", + "output": ".", + "recursive": true, + "loadVariables": ".env", + "fileTypes": [ + "markdown" + ] + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": [ + "md", + "markdown", + "mdx" + ], + "inlineStatements": { + "testStart": "", + "testEnd": "", + "ignoreStart": "", + "ignoreEnd": "", + "step": "" + }, + "markup": [ + { + "name": "onscreenText", + "regex": "\\*\\*.+?\\*\\*", + "actions": "find" + } + ] + } + ] + }, + { + "fileTypes": [ + { + "name": "Jupyter Notebooks", + "extensions": "ipynb", + "runShell": { + "command": "jupyter", + "args": [ + "nbconvert", + "--to", + "script", + "--execute", + "$1", + "--stdout" + ] + } + }, + { + "name": "JavaScript", + "extensions": "js", + "runShell": { + "command": "node $1" + } + }, + { + "name": "Python", + "extensions": "py", + "runShell": { + "command": "python $1" + } + } + ] + }, + { + "environment": { + "platform": "windows", + "arch": "x64" + } + }, + { + "concurrentRunners": 1 + }, + { + "concurrentRunners": true + }, + { + "concurrentRunners": 4 + }, + { + "debug": false + }, + { + "debug": true + }, + { + "debug": "stepThrough" + }, + { + "integrations": { + "docDetectiveApi": { + "apiKey": "your-api-key-here" + } + } + }, + { + "crawl": true + }, + { + "processDitaMaps": true + }, + { + "integrations": { + "heretto": [ + { + "name": "example", + "organizationId": "your-organization-id", + "username": "your-username", + "apiToken": "your-api-token" + } + ] + } + } + ] + }, + "specs": { + "description": "Test specifications that were performed.", + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "specification", + "type": "object", + "dynamicDefaults": { + "specId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/spec_v3.schema.json" + ] + }, + "specId": { + "type": "string", + "description": "Unique identifier for the test specification." + }, + "description": { + "type": "string", + "description": "Description of the test specification." + }, + "specPath": { + "type": "string", + "description": "Path to the test specification." + }, + "contentPath": { + "type": "string", + "description": "Path to the content that the specification is associated with." + }, + "runOn": { + "type": "array", + "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels.", + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "tests": { + "description": "[Tests](test) to perform.", + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "test", + "type": "object", + "description": "A Doc Detective test.", + "properties": { + "testId": { + "type": "string", + "description": "Unique identifier for the test." + }, + "description": { + "type": "string", + "description": "Description of the test." + }, + "contentPath": { + "type": "string", + "description": "Path to the content that the test is associated with." + }, + "detectSteps": { + "type": "boolean", + "description": "Whether or not to detect steps in input files based on markup regex.", + "default": true + }, + "runOn": { + "type": "array", + "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels.", + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "before": { + "type": "string", + "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec." + }, + "after": { + "type": "string", + "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec." + }, + "steps": { + "description": "Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed.", + "type": "array", + "minItems": 1, + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + }, + "contexts": { + "title": "Resolved contexts", + "type": "array", + "readOnly": true, + "description": "Resolved contexts to run the test in. This is a resolved version of the `runOn` property. It is not user-defined and should not be used in test specifications.", + "items": { + "type": "object", + "properties": { + "platform": { + "type": "string", + "description": "Platform to run the test on. This is a resolved version of the `platforms` property." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "steps": { + "description": "Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed.", + "type": "array", + "minItems": 1, + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + } + }, + "title": "Resolved context" + } + } + }, + "dynamicDefaults": { + "testId": "uuid" + }, + "anyOf": [ + { + "required": [ + "steps" + ] + }, + { + "required": [ + "contexts" + ] + } + ], + "additionalProperties": false, + "components": { + "schemas": { + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + } + } + }, + "examples": [ + { + "steps": [ + { + "checkLink": "https://www.duckduckgo.com" + } + ] + }, + { + "steps": [ + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": true, + "type": { + "keys": [ + "shorthair cats", + "$ENTER$" + ] + } + } + } + ] + }, + { + "testId": "Do all the things! - Test", + "description": "This test includes every property across all actions.", + "before": "setup.json", + "after": "cleanup.json", + "runOn": [ + { + "platforms": [ + "linux" + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } + } + ], + "steps": [ + { + "loadVariables": ".env" + }, + { + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + }, + { + "httpRequest": { + "method": "post", + "url": "https://reqres.in/api/users", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} + }, + { + "type": { + "keys": [ + "$ENTER$" + ] + } + }, + { + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } + } + ], + "detectSteps": true + }, + { + "testId": "c61b02e8-7485-44d3-8065-f873673379c6", + "openApi": [ + { + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "", + "name": "Acme" + } + ], + "steps": [ + { + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + } + ], + "detectSteps": true + } + ] + } + ] + } + } + }, + "required": [ + "tests" + ], + "examples": [ + { + "tests": [ + { + "steps": [ + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + } + ] + } + ] + }, + { + "specId": "Do all the things! - Spec", + "runOn": [ + { + "platforms": [ + "windows", + "mac" + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } + } + ], + "tests": [ + { + "testId": "Do all the things! - Test", + "description": "This test includes nearly every property across all actions.", + "runOn": [ + { + "platforms": "linux", + "browsers": "firefox" + } + ], + "steps": [ + { + "loadVariables": ".env" + }, + { + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + }, + { + "httpRequest": { + "method": "post", + "url": "https://reqres.in/api/users", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} + }, + { + "type": { + "keys": [ + "$ENTER$" + ] + } + }, + { + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } + } + ], + "detectSteps": true + } + ] + }, + { + "specId": "Make a request from an OpenAPI definition", + "openApi": [ + { + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com", + "name": "Acme" + } + ], + "tests": [ + { + "steps": [ + { + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + } + ] + } + ] + } + ] + } + ] + } + } + }, + "required": [ + "specs" + ], + "examples": [ + { + "config": { + "input": [ + "/home/hawkeyexl/Workspaces/resolver/dev/doc-content-yaml.md" + ], + "logLevel": "debug", + "output": ".", + "recursive": true, + "relativePathBase": "file", + "detectSteps": true, + "fileTypes": [ + { + "name": "markdown", + "extensions": [ + "md", + "markdown", + "mdx" + ], + "inlineStatements": { + "testStart": [ + "{\\/\\*\\s*test\\s+?([\\s\\S]*?)\\s*\\*\\/}", + "", + "\\[comment\\]:\\s+#\\s+\\(test\\s*(.*?)\\s*\\)", + "\\[comment\\]:\\s+#\\s+\\(test start\\s*(.*?)\\s*\\)" + ], + "testEnd": [ + "{\\/\\*\\s*test end\\s*\\*\\/}", + "", + "\\[comment\\]:\\s+#\\s+\\(test end\\)" + ], + "ignoreStart": [ + "{\\/\\*\\s*test ignore start\\s*\\*\\/}", + "" + ], + "ignoreEnd": [ + "{\\/\\*\\s*test ignore end\\s*\\*\\/}", + "" + ], + "step": [ + "{\\/\\*\\s*step\\s+?([\\s\\S]*?)\\s*\\*\\/}", + "", + "\\[comment\\]:\\s+#\\s+\\(step\\s*(.*?)\\s*\\)" + ] + }, + "markup": [ + { + "name": "checkHyperlink", + "regex": [ + "(?" + ], + "testEnd": [ + "" + ], + "ignoreStart": [ + "" + ], + "ignoreEnd": [ + "" + ], + "step": [ + "" + ] + }, + "markup": [] + } + ], + "telemetry": { + "send": true + }, + "configId": "3e467e5d-27cb-41f3-800f-aeb3c20dcb4c", + "environment": { + "arch": "x64", + "platform": "linux", + "workingDirectory": "/home/hawkeyexl/Workspaces/resolver" + } + }, + "specs": [ + { + "specId": "cc656bba-132f-4f0f-b093-2cfbdd784f69", + "contentPath": "/home/hawkeyexl/Workspaces/resolver/dev/doc-content-yaml.md", + "tests": [ + { + "testId": "doc-detective-docs", + "detectSteps": false, + "runOn": [], + "openApi": [], + "contexts": [ + { + "steps": [ + { + "checkLink": "https://doc-detective.com" + }, + { + "checkLink": "https://doc-detective.com/docs/get-started/intro" + }, + { + "goTo": "https://doc-detective.com/docs/get-started/actions/type" + }, + { + "find": "Special keys" + }, + { + "screenshot": "reference.png" + } + ], + "contextId": "eec1d123-7dfd-4362-b41a-942f36e0da5a" + } + ] + } + ], + "runOn": [], + "openApi": [] + } + ] + } + ] + }, + "report_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "report", + "type": "object", + "dynamicDefaults": { + "reportId": "uuid" + }, + "properties": { + "reportId": { + "type": "string", + "description": "Unique identifier for the test specification." + }, + "specs": { + "description": "Test specifications that were performed.", + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "specification", + "type": "object", + "dynamicDefaults": { + "specId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/spec_v3.schema.json" + ] + }, + "specId": { + "type": "string", + "description": "Unique identifier for the test specification." + }, + "description": { + "type": "string", + "description": "Description of the test specification." + }, + "specPath": { + "type": "string", + "description": "Path to the test specification." + }, + "contentPath": { + "type": "string", + "description": "Path to the content that the specification is associated with." + }, + "runOn": { + "type": "array", + "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels.", + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "tests": { + "description": "[Tests](test) to perform.", + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "test", + "type": "object", + "description": "A Doc Detective test.", + "properties": { + "testId": { + "type": "string", + "description": "Unique identifier for the test." + }, + "description": { + "type": "string", + "description": "Description of the test." + }, + "contentPath": { + "type": "string", + "description": "Path to the content that the test is associated with." + }, + "detectSteps": { + "type": "boolean", + "description": "Whether or not to detect steps in input files based on markup regex.", + "default": true + }, + "runOn": { + "type": "array", + "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels.", + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "before": { + "type": "string", + "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec." + }, + "after": { + "type": "string", + "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec." + }, + "steps": { + "description": "Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed.", + "type": "array", + "minItems": 1, + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + }, + "contexts": { + "title": "Resolved contexts", + "type": "array", + "readOnly": true, + "description": "Resolved contexts to run the test in. This is a resolved version of the `runOn` property. It is not user-defined and should not be used in test specifications.", + "items": { + "type": "object", + "properties": { + "platform": { + "type": "string", + "description": "Platform to run the test on. This is a resolved version of the `platforms` property." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "steps": { + "description": "Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed.", + "type": "array", + "minItems": 1, + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + } + }, + "title": "Resolved context" + } + } + }, + "dynamicDefaults": { + "testId": "uuid" + }, + "anyOf": [ + { + "required": [ + "steps" + ] + }, + { + "required": [ + "contexts" + ] + } + ], + "additionalProperties": false, + "components": { + "schemas": { + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + } + } + }, + "examples": [ + { + "steps": [ + { + "checkLink": "https://www.duckduckgo.com" + } + ] + }, + { + "steps": [ + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": true, + "type": { + "keys": [ + "shorthair cats", + "$ENTER$" + ] + } + } + } + ] + }, + { + "testId": "Do all the things! - Test", + "description": "This test includes every property across all actions.", + "before": "setup.json", + "after": "cleanup.json", + "runOn": [ + { + "platforms": [ + "linux" + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } + } + ], + "steps": [ + { + "loadVariables": ".env" + }, + { + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + }, + { + "httpRequest": { + "method": "post", + "url": "https://reqres.in/api/users", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} + }, + { + "type": { + "keys": [ + "$ENTER$" + ] + } + }, + { + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } + } + ], + "detectSteps": true + }, + { + "testId": "c61b02e8-7485-44d3-8065-f873673379c6", + "openApi": [ + { + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "", + "name": "Acme" + } + ], + "steps": [ + { + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + } + ], + "detectSteps": true + } + ] + } + ] + } + } + }, + "required": [ + "tests" + ], + "examples": [ + { + "tests": [ + { + "steps": [ + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + } + ] + } + ] + }, + { + "specId": "Do all the things! - Spec", + "runOn": [ + { + "platforms": [ + "windows", + "mac" + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } + } + ], + "tests": [ + { + "testId": "Do all the things! - Test", + "description": "This test includes nearly every property across all actions.", + "runOn": [ + { + "platforms": "linux", + "browsers": "firefox" + } + ], + "steps": [ + { + "loadVariables": ".env" + }, + { + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + }, + { + "httpRequest": { + "method": "post", + "url": "https://reqres.in/api/users", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} + }, + { + "type": { + "keys": [ + "$ENTER$" + ] + } + }, + { + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } + } + ], + "detectSteps": true + } + ] + }, + { + "specId": "Make a request from an OpenAPI definition", + "openApi": [ + { + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com", + "name": "Acme" + } + ], + "tests": [ + { + "steps": [ + { + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + } + ] + } + ] + } + ] + } + ] + } + } + }, + "required": [ + "specs" + ], + "examples": [ + { + "specs": [ + { + "tests": [ + { + "steps": [ + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + } + ] + } + ] + } + ] + }, + { + "specs": [ + { + "specId": "Do all the things! - Spec", + "runOn": [ + { + "platforms": [ + "windows", + "mac" + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } + } + ], + "tests": [ + { + "testId": "Do all the things! - Test", + "description": "This test includes nearly every property across all actions.", + "runOn": [ + { + "platforms": "linux", + "browsers": "firefox" + } + ], + "steps": [ + { + "loadVariables": ".env" + }, + { + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + }, + { + "httpRequest": { + "method": "post", + "url": "https://reqres.in/api/users", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} + }, + { + "type": { + "keys": [ + "$ENTER$" + ] + } + }, + { + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } + } + ], + "detectSteps": true + } + ] + } + ] + }, + { + "specs": [ + { + "specId": "Make a request from an OpenAPI definition", + "openApi": [ + { + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com", + "name": "Acme" + } + ], + "tests": [ + { + "steps": [ + { + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + } + ] + } + ] + } + ] + } + ] + }, + "runCode_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + }, + "runShell_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + }, + "saveCookie_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + }, + "screenshot_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + }, + "sourceIntegration_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "description": "Information about the source integration for a file, enabling upload of changed files back to the source CMS.", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + }, + "spec_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "specification", + "type": "object", + "dynamicDefaults": { + "specId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/spec_v3.schema.json" + ] + }, + "specId": { + "type": "string", + "description": "Unique identifier for the test specification." + }, + "description": { + "type": "string", + "description": "Description of the test specification." + }, + "specPath": { + "type": "string", + "description": "Path to the test specification." + }, + "contentPath": { + "type": "string", + "description": "Path to the content that the specification is associated with." + }, + "runOn": { + "type": "array", + "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels.", + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "tests": { + "description": "[Tests](test) to perform.", + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "test", + "type": "object", + "description": "A Doc Detective test.", + "properties": { + "testId": { + "type": "string", + "description": "Unique identifier for the test." + }, + "description": { + "type": "string", + "description": "Description of the test." + }, + "contentPath": { + "type": "string", + "description": "Path to the content that the test is associated with." + }, + "detectSteps": { + "type": "boolean", + "description": "Whether or not to detect steps in input files based on markup regex.", + "default": true + }, + "runOn": { + "type": "array", + "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels.", + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "before": { + "type": "string", + "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec." + }, + "after": { + "type": "string", + "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec." + }, + "steps": { + "description": "Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed.", + "type": "array", + "minItems": 1, + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + }, + "contexts": { + "title": "Resolved contexts", + "type": "array", + "readOnly": true, + "description": "Resolved contexts to run the test in. This is a resolved version of the `runOn` property. It is not user-defined and should not be used in test specifications.", + "items": { + "type": "object", + "properties": { + "platform": { + "type": "string", + "description": "Platform to run the test on. This is a resolved version of the `platforms` property." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "steps": { + "description": "Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed.", + "type": "array", + "minItems": 1, + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + } + }, + "title": "Resolved context" + } + } + }, + "dynamicDefaults": { + "testId": "uuid" + }, + "anyOf": [ + { + "required": [ + "steps" + ] + }, + { + "required": [ + "contexts" + ] + } + ], + "additionalProperties": false, + "components": { + "schemas": { + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + } + } + }, + "examples": [ + { + "steps": [ + { + "checkLink": "https://www.duckduckgo.com" + } + ] + }, + { + "steps": [ + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": true, + "type": { + "keys": [ + "shorthair cats", + "$ENTER$" + ] + } + } + } + ] + }, + { + "testId": "Do all the things! - Test", + "description": "This test includes every property across all actions.", + "before": "setup.json", + "after": "cleanup.json", + "runOn": [ + { + "platforms": [ + "linux" + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } + } + ], + "steps": [ + { + "loadVariables": ".env" + }, + { + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + }, + { + "httpRequest": { + "method": "post", + "url": "https://reqres.in/api/users", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} + }, + { + "type": { + "keys": [ + "$ENTER$" + ] + } + }, + { + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } + } + ], + "detectSteps": true + }, + { + "testId": "c61b02e8-7485-44d3-8065-f873673379c6", + "openApi": [ + { + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "", + "name": "Acme" + } + ], + "steps": [ + { + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + } + ], + "detectSteps": true + } + ] + } + ] + } + } + }, + "required": [ + "tests" + ], + "examples": [ + { + "tests": [ + { + "steps": [ + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + } + ] + } + ] + }, + { + "specId": "Do all the things! - Spec", + "runOn": [ + { + "platforms": [ + "windows", + "mac" + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } + } + ], + "tests": [ + { + "testId": "Do all the things! - Test", + "description": "This test includes nearly every property across all actions.", + "runOn": [ + { + "platforms": "linux", + "browsers": "firefox" + } + ], + "steps": [ + { + "loadVariables": ".env" + }, + { + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + }, + { + "httpRequest": { + "method": "post", + "url": "https://reqres.in/api/users", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} + }, + { + "type": { + "keys": [ + "$ENTER$" + ] + } + }, + { + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } + } + ], + "detectSteps": true + } + ] + }, + { + "specId": "Make a request from an OpenAPI definition", + "openApi": [ + { + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com", + "name": "Acme" + } + ], + "tests": [ + { + "steps": [ + { + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + } + ] + } + ] + } + ] + }, + "step_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + }, + "stopRecord_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + }, + "test_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "test", + "type": "object", + "description": "A Doc Detective test.", + "properties": { + "testId": { + "type": "string", + "description": "Unique identifier for the test." + }, + "description": { + "type": "string", + "description": "Description of the test." + }, + "contentPath": { + "type": "string", + "description": "Path to the content that the test is associated with." + }, + "detectSteps": { + "type": "boolean", + "description": "Whether or not to detect steps in input files based on markup regex.", + "default": true + }, + "runOn": { + "type": "array", + "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels.", + "items": { + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "context", + "type": "object", + "description": "A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment.", + "additionalProperties": false, + "dynamicDefaults": { + "contextId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json" + ] + }, + "contextId": { + "type": "string", + "description": "Unique identifier for the context." + }, + "platforms": { + "description": "Platforms to run tests on.", + "anyOf": [ + { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + ] + }, + "browsers": { + "description": "Browsers to run tests on.", + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + ] + } + } + ] + } + }, + "components": { + "schemas": { + "platform": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + }, + "browserName": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + } + } + }, + "examples": [ + { + "platforms": "linux", + "browsers": "chrome" + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" + ] + }, + { + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" + } + ] + }, + { + "platforms": [ + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } + }, + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "browsers": [ + { + "name": "chrome", + "headless": true, + "window": { + "width": 1920, + "height": 1080 + }, + "viewport": { + "width": 1600, + "height": 900 + } + }, + { + "name": "firefox", + "window": { + "width": 1366, + "height": 768 + } + }, + { + "name": "webkit", + "headless": false, + "viewport": { + "width": 1440, + "height": 900 + } + } + ] + }, + { + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "before": { + "type": "string", + "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec." + }, + "after": { + "type": "string", + "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec." + }, + "steps": { + "description": "Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed.", + "type": "array", + "minItems": 1, + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + }, + "contexts": { + "title": "Resolved contexts", + "type": "array", + "readOnly": true, + "description": "Resolved contexts to run the test in. This is a resolved version of the `runOn` property. It is not user-defined and should not be used in test specifications.", + "items": { + "type": "object", + "properties": { + "platform": { + "type": "string", + "description": "Platform to run the test on. This is a resolved version of the `platforms` property." + }, + "browser": { + "type": "object", + "description": "Browser configuration.", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the browser.", + "enum": [ + "chrome", + "firefox", + "safari", + "webkit" + ], + "$comment": "`safari` is just a shortcut for `webkit`. Included for visibility and to reduce questions." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode.", + "default": true + }, + "window": { + "type": "object", + "description": "Browser dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the browser window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the browser window in pixels." + } + }, + "title": "Browser Window" + }, + "viewport": { + "type": "object", + "description": "Viewport dimensions.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the viewport in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the viewport in pixels." + } + }, + "title": "Browser Viewport" + } + }, + "title": "Browser" + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + }, + "steps": { + "description": "Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed.", + "type": "array", + "minItems": 1, + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "step", + "description": "A step in a test.", + "type": "object", + "components": { + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + } + }, + "anyOf": [ + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "anyOf": [ + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "string", + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "Check link (detailed)", + "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + } + } + ], + "default": [ + 200, + 301, + 302, + 307, + 308 + ] + } + } + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com", + "statusCodes": 200 + }, + { + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + } + }, + "title": "checkLink" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "find" + ], + "properties": { + "find": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "find", + "description": "Find an element based on display text or a selector, then optionally interact with it.", + "anyOf": [ + { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + ], + "components": { + "schemas": { + "string": { + "title": "Find element (simple)", + "type": "string", + "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "object": { + "title": "Find element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "additionalProperties": false, + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to find. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view.", + "type": "boolean", + "default": true + }, + "click": { + "description": "Click the element.", + "anyOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + }, + { + "type": "boolean" + } + ], + "components": { + "schemas": { + "string": { + "title": "Click element (simple)", + "type": "string", + "description": "Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID." + }, + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "object": { + "title": "Click element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + }, + "elementText": { + "type": "string", + "description": "Display text of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "selector": { + "type": "string", + "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + }, + "examples": [ + true, + "right", + { + "button": "left", + "elementText": "Element text" + }, + { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + }, + { + "type": "object", + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + }, + "title": "Find element and click" + } + ] + }, + "type": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`type`](type). To type in the element, make the element active with the `click` parameter.", + "allOf": [ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } + } + ] + } + } + } + } + }, + "examples": [ + "Find me!", + { + "selector": "[title=Search]" + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + }, + { + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Go to URL (simple)", + "description": "Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any.", + "type": "string", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "timeout": { + "type": "integer", + "description": "Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails.", + "default": 30000, + "minimum": 0 + }, + "waitUntil": { + "type": "object", + "description": "Configuration for waiting conditions after navigation.", + "additionalProperties": false, + "properties": { + "networkIdleTime": { + "description": "Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "default": 1000 + }, + "find": { + "type": "object", + "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { + "type": "string", + "description": "CSS selector for the element to wait for." + }, + "elementText": { + "type": "string", + "description": "Text content the element must contain. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + } + } + } + } + }, + "title": "Go to URL (detailed)" + } + } + }, + "examples": [ + "https://www.google.com", + "/search", + { + "url": "https://www.google.com" + }, + { + "url": "/search", + "origin": "https://www.google.com" + }, + { + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } + }, + { + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" + } + } + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, + { + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } + }, + { + "url": "http://localhost:8092", + "waitUntil": { + "find": { + "selector": "button", + "elementText": "Standard Button", + "elementTestId": "standard-btn", + "elementAria": "Sample Standard Button", + "elementId": "standard-btn", + "elementClass": [ + "btn" + ], + "elementAttribute": { + "type": "button", + "value": "Standard Button" + } + } + } + } + ] + } + }, + "title": "goTo" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "httpRequest" + ], + "properties": { + "httpRequest": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", + "anyOf": [ + { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + ], + "components": { + "schemas": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "type": "string", + "description": "ID of the operation to use for the request." + }, + { + "title": "Operation ID", + "description": "Operation ID from the OpenAPI schema. Only valid if the OpenAPI description path is specified elsewhere and the operation ID is unique among all specified OpenAPI descriptions." + } + ] + }, + { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ], + "title": "OpenAPI definition (httpRequest)" + } + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "request": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, + "anyOf": [ + { + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request headers (string)", + "description": "Headers to include in the HTTP request, as return-separated values. For example, `Content-Type: application/json\nAuthorization: Bearer token`.", + "type": "string" + } + ] + }, + "parameters": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {}, + "title": "Request parameters" + }, + "body": { + "description": "The body of the HTTP request.", + "anyOf": [ + { + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} + }, + { + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} + }, + { + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" + } + ], + "default": {} + } + }, + "title": "Request" + }, + "response": { + "type": "object", + "additionalProperties": false, + "properties": { + "headers": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {}, + "title": "Response headers" + }, + "body": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "anyOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." + }, + { + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} + }, + { + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" + } + ], + "default": {} + }, + "required": { + "type": "array", + "description": "Array of field paths that must exist in the response body. Uses dot notation for nested fields (e.g., 'user.name') and bracket notation for array indices (e.g., 'items[0].id'). Fields must be present but may have any value including null.", + "items": { + "type": "string" + }, + "default": [] + } + }, + "title": "Response" + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in the response body.", + "default": true + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + } + } + } + } + }, + "examples": [ + "https://reqres.in/api/users", + { + "url": "https://reqres.in/api/users" + }, + { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, + { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + }, + { + "openApi": "getUserById" + }, + { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + }, + { + "url": "https://www.api-server.com", + "method": "post", + "request": { + "headers": "Content-Type: application/json\\nAuthorization: Bearer token" + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "id", + "email", + "createdAt" + ] + } + }, + { + "url": "https://api.example.com/users/123", + "response": { + "required": [ + "user.profile.name", + "user.profile.avatar", + "user.settings.notifications" + ] + } + }, + { + "url": "https://api.example.com/orders", + "response": { + "required": [ + "orders[0].id", + "orders[0].total", + "orders[0].items[0].productId" + ] + } + }, + { + "url": "https://api.example.com/users", + "response": { + "required": [ + "sessionToken", + "expiresAt", + "user.id" + ], + "body": { + "status": "success", + "user": { + "role": "admin" + } + } + } + } + ] + } + }, + "title": "httpRequest" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runShell", + "description": "Perform a native shell command.", + "anyOf": [ + { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "required": [ + "command" + ], + "additionalProperties": false, + "properties": { + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run shell command (detailed)" + } + } + }, + "examples": [ + "docker run hello-world", + { + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "command": "echo", + "args": [ + "hello-world" + ] + }, + { + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" + }, + { + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + ], + "components": { + "schemas": { + "object": { + "type": "object", + "required": [ + "code", + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "Language of the code to run.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "description": "Code to run.", + "type": "string" + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "anyOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "stdio": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "path": { + "type": "string", + "description": "File path to save the command's output, relative to `directory`." + }, + "directory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `path` if it exists.\nIf `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + } + }, + "title": "Run code (detailed)" + } + } + }, + "examples": [ + { + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "stdio": "Hello from Docker!" + }, + { + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + ] + } + }, + "title": "runCode" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "screenshot" + ], + "properties": { + "screenshot": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "screenshot", + "description": "Takes a screenshot in PNG format.", + "anyOf": [ + { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + { + "type": "boolean", + "title": "Capture screenshot", + "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + } + ], + "components": { + "schemas": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "title": "Screenshot (simple)", + "description": "File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step.", + "type": "string", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 0.05, + "minimum": 0, + "maximum": 1 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "aboveVariation" + ], + "default": "aboveVariation" + }, + "crop": { + "anyOf": [ + { + "title": "Crop by element (simple)", + "type": "string", + "description": "Display text or selector of the element to screenshot." + }, + { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + } + ] + }, + "sourceIntegration": { + "description": "Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations.", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "sourceIntegration", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "integrationName" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of integration. Currently supported: 'heretto'. Additional types may be added in the future.", + "enum": [ + "heretto" + ] + }, + "integrationName": { + "type": "string", + "description": "The name of the integration configuration in the config file. Used to look up authentication credentials." + }, + "fileId": { + "type": "string", + "description": "The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path." + }, + "filePath": { + "type": "string", + "description": "The path of the file in the source CMS. Used for lookup if fileId is not available." + }, + "contentPath": { + "type": "string", + "description": "The local path to the file that references this source. Used for resolving relative paths." + } + }, + "examples": [ + { + "type": "heretto", + "integrationName": "my-heretto", + "fileId": "8f3ed200-cbba-11e1-ac51-c82a1446d15c", + "filePath": "/db/organizations/example/repositories/docs/images/screenshot.png" + }, + { + "type": "heretto", + "integrationName": "my-heretto", + "filePath": "images/screenshot.png", + "contentPath": "/tmp/doc-detective/heretto_abc123/topic.dita" + } + ] + } + }, + "title": "Capture screenshot (detailed)" + }, + "crop_element": { + "title": "Crop by element (detailed)", + "type": "object", + "description": "Crop the screenshot to a specific element.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text of the element to screenshot." + }, + "selector": { + "type": "string", + "description": "Selector of the element to screenshot." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "padding": { + "anyOf": [ + { + "title": "Padding (simple)", + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + ] + } + } + }, + "padding": { + "type": "object", + "additionalProperties": false, + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + }, + "title": "Padding (detailed)", + "description": "Padding in pixels to add to the bounds of the element." + } + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + }, + { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + ] + } + }, + "title": "screenshot" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "saveCookie" + ], + "properties": { + "saveCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "saveCookie", + "description": "Save a specific browser cookie to a file or environment variable for later reuse.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save. Will be saved to a default file path or environment variable.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to save.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name to store the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to save the cookie, relative to directory. Uses Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory to save the cookie file. If not specified, uses output directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "boolean", + "title": "Overwrite existing file", + "description": "Whether to overwrite existing cookie file.", + "default": false + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by (optional).", + "transform": [ + "trim" + ] + } + }, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "title": "Save cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "test_env_cookie", + { + "name": "auth_cookie", + "path": "auth-cookie.txt" + }, + { + "name": "session_token", + "variable": "SESSION_TOKEN" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true + }, + { + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true + }, + { + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "record" + ], + "properties": { + "record": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "record", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "anyOf": [ + { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + }, + { + "type": "boolean", + "title": "Record (boolean)", + "description": "If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport." + } + ], + "components": { + "schemas": { + "string": { + "title": "Record (simple)", + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "description": "Directory of the file. If the directory doesn't exist, creates the directory.", + "transform": [ + "trim" + ] + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] + } + }, + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ + { + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadVariables", + "type": "string", + "description": "Load environment variables from the specified `.env` file.", + "examples": [ + ".env" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "dragAndDrop", + "type": "object", + "required": [ + "dragAndDrop" + ], + "properties": { + "dragAndDrop": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "dragAndDrop", + "description": "Drag and drop an element from source to target.", + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "description": "The element to drag.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "target": { + "description": "The target location to drop the element.", + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + ] + }, + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + }, + "object": { + "title": "Element (detailed)", + "type": "object", + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "elementText": { + "type": "string", + "description": "Display text or regex pattern (enclosed in forward slashes) of the element. If combined with `selector`, the element must match both the text and the selector." + }, + "selector": { + "type": "string", + "description": "Selector of the element. If combined with `elementText`, the element must match both the text and the selector." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + } + } + } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" + }, + { + "source": ".draggable-block", + "target": ".drop-zone", + "duration": 2000 + }, + { + "source": { + "selector": ".widget", + "elementText": "Data Table" + }, + "target": { + "selector": "#design-canvas" + }, + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 + }, + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "loadCookie", + "type": "object", + "required": [ + "loadCookie" + ], + "properties": { + "loadCookie": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "loadCookie", + "description": "Load a specific cookie from a file or environment variable into the browser.", + "anyOf": [ + { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + ], + "components": { + "schemas": { + "string": { + "type": "string", + "title": "Cookie name or file path", + "description": "Name of the specific cookie to load from default location, or file path to cookie file.", + "pattern": "^[A-Za-z0-9_./\\-]+$", + "transform": [ + "trim" + ] + }, + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } + }, + { + "required": [ + "variable" + ], + "not": { + "anyOf": [ + { + "required": [ + "path" + ] + }, + { + "required": [ + "directory" + ] + } + ] + } + } + ], + "properties": { + "$schema": { + "description": "Optional self-describing schema URI for linters", + "type": "string", + "format": "uri-reference" + }, + "name": { + "type": "string", + "title": "Cookie name", + "description": "Name of the specific cookie to load.", + "pattern": "^[A-Za-z0-9_.-]+$", + "transform": [ + "trim" + ] + }, + "variable": { + "type": "string", + "title": "Environment variable name", + "description": "Environment variable name containing the cookie as JSON string.", + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", + "transform": [ + "trim" + ] + }, + "path": { + "type": "string", + "title": "Cookie file path", + "description": "File path to cookie file, relative to directory. Supports Netscape cookie format.", + "transform": [ + "trim" + ] + }, + "directory": { + "type": "string", + "title": "Directory path", + "description": "Directory containing the cookie file.", + "transform": [ + "trim" + ] + }, + "domain": { + "type": "string", + "title": "Cookie domain", + "description": "Specific domain to filter the cookie by when loading from multi-cookie file (optional).", + "transform": [ + "trim" + ] + } + }, + "title": "Load cookie (detailed)" + } + } + }, + "examples": [ + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", + { + "name": "auth_cookie", + "variable": "AUTH_COOKIE" + }, + { + "name": "test_cookie", + "path": "test-cookie.txt" + }, + { + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" + }, + { + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" + }, + "properties": { + "$schema": { + "description": "JSON Schema for this object.", + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] + }, + "stepId": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "unsafe": { + "type": "boolean", + "description": "Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag.", + "default": false + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Outputs (step)" + }, + "variables": { + "type": "object", + "description": "Environment variables to set from user-defined expressions.", + "default": {}, + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "title": "Variables (step)" + }, + "breakpoint": { + "type": "boolean", + "description": "Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled.", + "default": false + } + }, + "title": "Common" + }, + { + "title": "wait", + "type": "object", + "required": [ + "wait" + ], + "properties": { + "wait": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + } + } + } + ] + } + ], + "examples": [ + { + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } + }, + { + "checkLink": "https://www.google.com" + }, + { + "stepId": "path-only", + "checkLink": "/search" + }, + { + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } + }, + { + "goTo": { + "url": "https://www.google.com" + } + }, + { + "goTo": "https://www.google.com" + }, + { + "wait": 5000 + }, + { + "runCode": { + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "stopRecord": true + }, + { + "screenshot": true + }, + { + "screenshot": "image.png" + }, + { + "screenshot": "static/images/image.png" + }, + { + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } + }, + { + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "padding": { + "top": 0, + "right": 0, + "bottom": 0, + "left": 0 + } + } + } + }, + { + "record": true + }, + { + "record": "video.mp4" + }, + { + "record": "static/media/video.mp4" + }, + { + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" + }, + { + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } + }, + { + "loadVariables": "variables.env" + }, + { + "saveCookie": "session_token" + }, + { + "saveCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data", + "overwrite": true + } + }, + { + "loadCookie": "session_token" + }, + { + "loadCookie": { + "name": "auth_cookie", + "path": "auth-session.txt", + "directory": "./test-data" + } + }, + { + "find": "Find me!" + }, + { + "find": { + "selector": "[title=Search]" + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } + }, + { + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } + }, + { + "click": true + }, + { + "click": "right" + }, + { + "click": { + "button": "left", + "elementText": "Element text" + } + }, + { + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + }, + { + "httpRequest": "https://reqres.in/api/users" + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users" + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } + }, + { + "httpRequest": { + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + } + }, + { + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + }, + { + "httpRequest": { + "openApi": "getUserById" + } + }, + { + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } + }, + { + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } + }, + { + "stepId": "breakpoint-example", + "description": "Step with breakpoint enabled", + "goTo": "https://www.example.com", + "breakpoint": true + }, + { + "checkLink": "https://www.google.com", + "breakpoint": false + }, + { + "dragAndDrop": { + "source": { + "selector": "#sourceElement" + }, + "target": { + "selector": "#targetElement" + } + } + } + ] + } + } + }, + "title": "Resolved context" + } + } + }, + "dynamicDefaults": { + "testId": "uuid" + }, + "anyOf": [ + { + "required": [ + "steps" + ] + }, + { + "required": [ + "contexts" + ] + } + ], + "additionalProperties": false, + "components": { + "schemas": { + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + }, + "definition": { + "type": "object", + "readOnly": true, + "description": "OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined.", + "additionalProperties": true, + "title": "OpenAPI definition" + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "headers": { + "type": "object", + "description": "Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + }, + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI description." + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + }, + { + "name": "Reqres", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true + }, + { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none", + "mockResponse": true, + "headers": { + "Authorization": "Bearer 12345" + } + } + ] + }, + { + "type": "object", + "not": { + "required": [ + "operationId" + ] + }, + "required": [ + "name", + "descriptionPath" + ], + "title": "OpenAPI description (test)" + } + ] + } + } + } + }, + "examples": [ + { + "steps": [ + { + "checkLink": "https://www.duckduckgo.com" + } + ] + }, + { + "steps": [ + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "click": true, + "type": { + "keys": [ + "shorthair cats", + "$ENTER$" + ] + } + } + } + ] + }, + { + "testId": "Do all the things! - Test", + "description": "This test includes every property across all actions.", + "before": "setup.json", + "after": "cleanup.json", + "runOn": [ + { + "platforms": [ + "linux" + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } + } + ], + "steps": [ + { + "loadVariables": ".env" + }, + { + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "checkLink": { + "url": "https://www.duckduckgo.com" + } + }, + { + "httpRequest": { + "method": "post", + "url": "https://reqres.in/api/users", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + }, + { + "goTo": { + "url": "https://www.duckduckgo.com" + } + }, + { + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} + }, + { + "type": { + "keys": [ + "$ENTER$" + ] + } + }, + { + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } + } + ], + "detectSteps": true + }, + { + "testId": "c61b02e8-7485-44d3-8065-f873673379c6", + "openApi": [ + { + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "", + "name": "Acme" + } + ], + "steps": [ + { + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} + } + ], + "detectSteps": true + } + ] + }, + "type_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "typeKeys", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`.", + "anyOf": [ + { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 + }, + "selector": { + "type": "string", + "description": "Selector for the element to type into. If not specified, the typing occurs in the active element." + }, + "elementText": { + "type": "string", + "description": "Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria." + }, + "elementId": { + "type": "string", + "description": "ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementTestId": { + "type": "string", + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." + }, + "elementClass": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } + }, + "required": [ + "keys" + ], + "additionalProperties": false + } + } + }, + "examples": [ + "kittens", + [ + "$ENTER$" + ], + [ + "kittens", + "$ENTER$" + ], + { + "keys": "kittens" + }, + { + "keys": [ + "$ENTER$" + ] + }, + { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + }, + "wait_v3": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "wait", + "description": "Pause (in milliseconds) before performing the next action.", + "default": 5000, + "anyOf": [ + { + "type": "number", + "title": "Wait (simple)" + }, + { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + { + "type": "boolean", + "title": "Wait (boolean)" + } + ], + "components": { + "schemas": { + "string": { + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + } + } + }, + "examples": [ + 5000, + "$WAIT_DURATION", + true + ] + }, + "checkLink_v2": { + "title": "checkLink", + "type": "object", + "description": "Check if a URL returns an acceptable status code from a GET request.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "checkLink", + "description": "Action to perform." + }, + "url": { + "type": "string", + "description": "URL to check.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201, + 202 + ] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "url" + ], + "additionalProperties": false, + "examples": [ + { + "action": "checkLink", + "url": "https://www.google.com" + }, + { + "action": "checkLink", + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + }, + { + "action": "checkLink", + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + }, + "config_v2": { + "title": "config", + "description": "Configuration options for Doc Detective operations.", + "type": "object", + "additionalProperties": false, + "properties": { + "defaultCommand": { + "description": "Default command to run when no command is specified.", + "type": "string", + "enum": [ + "runTests", + "runCoverage" + ] + }, + "input": { + "default": ".", + "description": "Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "output": { + "default": ".", + "description": "Path of the of the file or directory in which to store the output of Doc Detective commands. If a file path is specified, the output is written to that file. If a file of that name already exists, Doc Detective creates appends an integer to the result file name. If a directory path is specified, the output file name is dependent on the command being run.", + "type": "string" + }, + "recursive": { + "default": true, + "description": "If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specificaions and source files.", + "type": "boolean" + }, + "relativePathBase": { + "description": "Whether paths should be interpreted as relative to the current working directory (`cwd`) or to the file in which they're specified (`file`).", + "type": "string", + "enum": [ + "cwd", + "file" + ], + "default": "cwd" + }, + "envVariables": { + "description": "Path to a `.env` file to load before performing a Doc Detective operation.", + "type": "string" + }, + "runTests": { + "type": "object", + "additionalProperties": false, + "description": "Options for running tests. When running tests, values set here override general configuration options.", + "properties": { + "input": { + "description": "Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "output": { + "description": "Path of the of the file or directory in which to store the output of Doc Detective commands. If a file path is specified, the output is written to that file. If a file of that name already exists, Doc Detective creates appends an integer to the result file name. If a directory path is specified, the output file name is dependent on the command being run.", + "type": "string", + "default": "." + }, + "setup": { + "description": "Path(s) to test specifications to perform before those specified by `input`. Useful for setting up testing environments.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "cleanup": { + "description": "Path(s) to test specifications to perform after those specified by `input`. Useful for cleaning up testing environments.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "recursive": { + "description": "If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specificaions and source files.", + "type": "boolean" + }, + "detectSteps": { + "type": "boolean", + "description": "Whether or not to detect steps in input files based on markup regex.", + "default": false + }, + "mediaDirectory": { + "description": "DEPRECATED.", + "type": "string", + "default": "." + }, + "downloadDirectory": { + "description": "Path of the directory in which to store downloaded files.", + "type": "string", + "default": "." + }, + "contexts": { + "type": "array", + "description": "Application/platform sets to run tests in. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it.", + "items": { + "oneOf": [ + { + "title": "context", + "type": "object", + "description": "An application and supported platforms.\n\nIf no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For browsers, context priority is Firefox > Chrome > Chromium.", + "properties": { + "app": { + "type": "object", + "description": "The application to run.", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the application.", + "enum": [ + "chrome", + "firefox", + "safari", + "edge" + ] + }, + "path": { + "type": "string", + "description": "Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped." + }, + "options": { + "type": "object", + "description": "Options to pass to the app. Only works when `name` is `firefox` or `chrome`.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the window in pixels." + }, + "viewport_height": { + "type": "integer", + "description": "Height of the viewport in pixels. Overrides `height`." + }, + "viewport_width": { + "type": "integer", + "description": "Width of the viewport in pixels. Overrides `width`." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode. Not supported by Safari." + }, + "driverPath": { + "type": "string", + "description": "Path to the browser driver. If not specified, defaults to internally managed dependencies." + } + } + } + } + }, + "platforms": { + "description": "Supported platforms for the application.", + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + }, + "required": [ + "app", + "platforms" + ], + "additionalProperties": false, + "examples": [ + { + "app": { + "name": "chrome" + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "chrome", + "options": { + "viewport_width": 800, + "viewport_height": 600 + } + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "firefox", + "options": { + "width": 800, + "height": 600, + "headless": false, + "driverPath": "/usr/bin/geckodriver" + } + }, + "platforms": [ + "linux", + "windows", + "mac" + ] + }, + { + "app": { + "name": "safari" + }, + "platforms": [ + "mac" + ] + }, + { + "app": { + "name": "firefox", + "path": "/usr/bin/firefox" + }, + "platforms": [ + "linux" + ] + } + ] + } + ] + }, + "default": [ + { + "app": { + "name": "firefox", + "options": { + "width": 1200, + "height": 800, + "headless": true + } + }, + "platforms": [ + "linux", + "mac", + "windows" + ] + } + ] + } + } + }, + "runCoverage": { + "description": "Options for performing test coverage analysis on documentation source files. When performing coveration analysis, values set here override general configuration options.", + "type": "object", + "additionalProperties": false, + "properties": { + "input": { + "description": "Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "output": { + "description": "Path of the of the file or directory in which to store the output of Doc Detective commands. If a file path is specified, the output is written to that file. If a file of that name already exists, Doc Detective creates appends an integer to the result file name. If a directory path is specified, the output file name is dependent on the command being run.", + "type": "string", + "default": "." + }, + "recursive": { + "description": "If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specificaions and source files.", + "type": "boolean" + }, + "markup": { + "default": [ + "onscreenText", + "emphasis", + "image", + "hyperlink", + "codeInline", + "codeBlock", + "interaction" + ], + "description": "Markup types to include when performing this operation. If no markup types are specified, the operation includes all markup types as defined in `fileTypes`.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + } + }, + "suggestTests": { + "description": "Options for suggesting tests based on documentation source files. When suggesting tests, values set here override general condiguration options.", + "type": "object", + "additionalProperties": false, + "properties": { + "input": { + "description": "Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "output": { + "description": "Path of the of the file or directory in which to store the output of Doc Detective commands. If a file path is specified, the output is written to that file. If a file of that name already exists, Doc Detective creates appends an integer to the result file name. If a directory path is specified, the output file name is dependent on the command being run.", + "type": "string", + "default": "." + }, + "recursive": { + "description": "If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specificaions and source files.", + "type": "boolean" + }, + "markup": { + "default": [ + "onscreenText", + "emphasis", + "image", + "hyperlink", + "codeInline", + "codeBlock", + "interaction" + ], + "description": "Markup types to include when performing this operation. If no markup types are specified, the operation includes all markup types as defined in `fileTypes`.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + } + }, + "fileTypes": { + "description": "Information on supported file types and how to parse the markup within them.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "description": "Name of the file type.", + "type": "string" + }, + "extensions": { + "description": "File extensions to support with this configuration.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + }, + "testStartStatementOpen": { + "description": "Opening of an in-document test start statement.", + "type": "string" + }, + "testStartStatementClose": { + "description": "Close of an in-document test start statement.", + "type": "string" + }, + "testIgnoreStatement": { + "description": "Text for an in-document test ignore statement.", + "type": "string" + }, + "testEndStatement": { + "description": "Text for an in-document test end statement.", + "type": "string" + }, + "stepStatementOpen": { + "description": "Opening of an in-document step statement.", + "type": "string" + }, + "stepStatementClose": { + "description": "Close of an in-document step statement.", + "type": "string" + }, + "markup": { + "description": "Markup types and associated regex patterns to find in documentation source files.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "description": "Name of the markup type.", + "type": "string" + }, + "regex": { + "description": "Regex patterns to find the markup type in documentation source files.", + "type": "array", + "minItems": 1, + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + }, + "actions": { + "description": "Actions that apply to the markup type.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "string", + "enum": [ + "checkLink", + "find", + "goTo", + "httpRequest", + "runShell", + "saveScreenshot", + "setVariables", + "startRecording", + "stopRecording", + "typeKeys", + "wait" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "description": "Name of the action.", + "type": "string", + "enum": [ + "checkLink", + "find", + "goTo", + "httpRequest", + "runShell", + "saveScreenshot", + "setVariables", + "startRecording", + "stopRecording", + "typeKeys", + "wait" + ] + }, + "params": { + "description": "Parameters for the action.", + "type": "object", + "additionalProperties": true + } + }, + "required": [ + "name" + ] + }, + { + "title": "checkLink", + "type": "object", + "description": "Check if a URL returns an acceptable status code from a GET request.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "checkLink", + "description": "Action to perform." + }, + "url": { + "type": "string", + "description": "URL to check.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201, + 202 + ] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "url" + ], + "additionalProperties": false, + "examples": [ + { + "action": "checkLink", + "url": "https://www.google.com" + }, + { + "action": "checkLink", + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + }, + { + "action": "checkLink", + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + }, + { + "title": "find", + "type": "object", + "description": "Check if an element exists with the specified CSS selector.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "find", + "description": "Action to perform." + }, + "selector": { + "description": "Selector that uniquely identifies the element.", + "type": "string" + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "matchText": { + "type": "string", + "description": "Text that the element should contain. If the element doesn't contain the text, the step fails. Accepts both strings an regular expressions. To use a regular expression, the expression should start and end with a `/`. For example, `/search/`." + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view. Only runs the if the test is being recorded.", + "oneOf": [ + { + "type": "boolean" + } + ], + "default": false + }, + "click": { + "description": "Click the element.", + "oneOf": [ + { + "type": "boolean", + "default": false + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + } + } + ] + }, + "typeKeys": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`typeKeys`](typeKeys). To type in the element, make the element active with the `click` parameter.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "keys": { + "description": "String of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "delay": { + "type": "number", + "description": "Delay in milliseconds between each key press. Only valid during a recording.", + "default": 100 + } + } + } + ] + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the element's text.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the element's text.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + } + }, + "required": [ + "action", + "selector" + ], + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "examples": [ + { + "action": "find", + "selector": "[title=Search]" + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": "shorthair cat" + }, + { + "action": "find", + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": { + "keys": [ + "shorthair cat" + ], + "delay": 100 + } + }, + { + "action": "find", + "selector": "[title=ResultsCount]", + "setVariables": [ + { + "name": "resultsCount", + "regex": ".*" + } + ] + } + ] + }, + { + "title": "goTo", + "type": "object", + "description": "Navigate to a specified URL.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "goTo", + "description": "Action to perform." + }, + "url": { + "type": "string", + "description": "URL to navigate to.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "url" + ], + "additionalProperties": false, + "examples": [ + { + "action": "goTo", + "url": "https://www.google.com" + }, + { + "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", + "description": "This is a test!", + "action": "goTo", + "url": "https://www.google.com" + }, + { + "id": "ddec5e20-2e81-4f38-867c-92c8d9516756", + "description": "This is a test!", + "action": "goTo", + "url": "/search", + "origin": "https://www.google.com" + } + ] + }, + { + "title": "httpRequest", + "type": "object", + "description": "Perform a generic HTTP request, for example to an API.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "httpRequest", + "description": "Aciton to perform." + }, + "url": { + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI definition and configuration.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI definition, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI definition." + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "requestHeaders": { + "type": "object", + "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "requestHeaders": { + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {} + }, + "responseHeaders": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {} + }, + "requestParams": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "responseParams": { + "description": "DEPRECATED.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "requestData": { + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "responseData": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in `responseData`.", + "default": true + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "envsFromResponseData": { + "description": "Environment variables to set based on response variables, as an object of the environment variable name and the jq filter applied to the response data to identify the variable's value.", + "type": "array", + "default": [], + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "jqFilter": { + "description": "jq filter to apply to the response data. If the filter doesn't return a value, the environment variable isn't set.", + "type": "string" + } + }, + "required": [ + "name", + "jqFilter" + ] + } + ] + } + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "httpRequest", + "url": "https://reqres.in/api/users" + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users/2", + "method": "put", + "requestData": { + "name": "morpheus", + "job": "zion resident" + } + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "action": "httpRequest", + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "requestHeaders": { + "header": "value" + }, + "requestParams": { + "param": "value" + }, + "requestData": { + "field": "value" + }, + "responseHeaders": { + "header": "value" + }, + "responseData": { + "field": "value" + }, + "statusCodes": [ + 200 + ] + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ], + "savePath": "response.json", + "saveDirectory": "media", + "maxVariation": 5, + "overwrite": "byVariation" + }, + { + "action": "httpRequest", + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "requestHeaders": { + "Authorization": "Bearer $TOKEN" + } + } + } + ] + }, + { + "title": "runShell", + "type": "object", + "description": "Perform a native shell command.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "runShell", + "description": "The action to perform." + }, + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "output": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the command's output.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the command's output.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "required": [ + "action", + "command" + ], + "examples": [ + { + "action": "runShell", + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "hello-world" + ], + "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", + "description": "This is a test!" + }, + { + "action": "runShell", + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!" + }, + { + "action": "runShell", + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "output": "/.*?/", + "setVariables": [ + { + "name": "TEST", + "regex": ".*" + } + ] + }, + { + "action": "runShell", + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!", + "savePath": "docker-output.txt", + "saveDirectory": "output", + "maxVariation": 10, + "overwrite": "byVariation" + } + ] + }, + { + "title": "saveScreenshot", + "type": "object", + "description": "Takes a screenshot in PNG format.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "saveScreenshot", + "description": "The action to perform." + }, + "path": { + "type": "string", + "description": "File path of the PNG file, relative to `directory`. If not specified, the file name is the ID of the step.", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)" + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the exisitng screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 5, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `byVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "crop": { + "type": "object", + "description": "Crops the screenshot.", + "properties": { + "selector": { + "type": "string", + "description": "Selector of the element to crop the image to." + }, + "padding": { + "oneOf": [ + { + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + } + } + ] + } + }, + "required": [ + "selector" + ], + "additionalProperties": false + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "saveScreenshot" + }, + { + "action": "saveScreenshot", + "path": "results.png" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "maxVariation": 10, + "overwrite": "byVariation" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element" + } + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element", + "padding": 10 + } + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element", + "padding": { + "top": 10, + "right": 20, + "bottom": 30, + "left": 40 + } + } + } + ] + }, + { + "title": "setVariables", + "type": "object", + "description": "Load environment variables from a `.env` file.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "setVariables", + "description": "Action to perform." + }, + "path": { + "type": "string", + "description": "Path to the `.env` file." + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "path" + ], + "additionalProperties": false, + "examples": [ + { + "action": "setVariables", + "path": ".env" + } + ] + }, + { + "title": "startRecording", + "type": "object", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecording` action. Only runs when the context `app` is `chrome` and `headless` is `false`. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "startRecording", + "description": "The action to perform." + }, + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)" + }, + "directory": { + "type": "string", + "description": "Directory of the file. Attempts to create the directory if it doesn't exist." + }, + "overwrite": { + "type": "boolean", + "description": "If `true`, overwrites the existing file at `path` if it exists.", + "default": false + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "startRecording" + }, + { + "action": "startRecording", + "path": "results.mp4" + }, + { + "action": "startRecording", + "path": "results.mp4", + "directory": "static/media", + "overwrite": true + } + ] + }, + { + "title": "stopRecording", + "type": "object", + "description": "Stop the current recording.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "stopRecording", + "description": "The action to perform." + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "stopRecording" + } + ] + }, + { + "title": "typeKeys", + "type": "object", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's enum. For example, to type the Escape key, enter `$ESCAPE$`.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "typeKeys", + "description": "The action to perform." + }, + "keys": { + "description": "String of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "delay": { + "type": "number", + "description": "Delay in milliseconds between each key press. Only valid during a recording.", + "default": 100 + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "keys" + ], + "additionalProperties": false, + "examples": [ + { + "action": "typeKeys", + "keys": "kittens" + }, + { + "action": "typeKeys", + "keys": [ + "$ENTER$" + ] + }, + { + "action": "typeKeys", + "keys": [ + "kittens", + "$ENTER$" + ], + "delay": 500 + } + ] + }, + { + "title": "wait", + "type": "object", + "description": "Pause before performing the next action.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "wait", + "description": "The action to perform." + }, + "duration": { + "type": "number", + "description": "Milliseconds to wait.", + "default": 5000 + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "wait" + }, + { + "action": "wait", + "duration": 5000 + } + ] + } + ] + } + } + }, + "required": [ + "name", + "regex" + ] + } + ] + } + } + }, + "required": [ + "extensions", + "testStartStatementOpen", + "testStartStatementClose", + "testIgnoreStatement", + "testEndStatement", + "stepStatementOpen", + "stepStatementClose", + "markup" + ] + } + ] + }, + "default": [ + { + "name": "Markdown", + "extensions": [ + ".md", + ".markdown", + ".mdx" + ], + "testStartStatementOpen": "[comment]: # (test start", + "testStartStatementClose": ")", + "testIgnoreStatement": "[comment]: # (test ignore)", + "testEndStatement": "[comment]: # (test end)", + "stepStatementOpen": "[comment]: # (step", + "stepStatementClose": ")", + "markup": [ + { + "name": "onscreenText", + "regex": [ + "\\*\\*.+?\\*\\*" + ], + "actions": [ + "find" + ] + }, + { + "name": "emphasis", + "regex": [ + "(?", + "testIgnoreStatement": "", + "testEndStatement": "", + "stepStatementOpen": "", + "markup": [] + } + ] + }, + "integrations": { + "description": "Options for connecting to external services.", + "type": "object", + "additionalProperties": false, + "properties": { + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI definition and configuration.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI definition, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI definition." + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "requestHeaders": { + "type": "object", + "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + } + ] + }, + { + "type": "object", + "properties": { + "operationId": { + "type": "null", + "$commment": "Only allow operationId at the step level." + } + }, + "required": [ + "name", + "descriptionPath" + ] + } + ] + } + } + } + }, + "telemetry": { + "description": "Options around sending telemetry for Doc Detective usage.", + "type": "object", + "additionalProperties": false, + "properties": { + "send": { + "description": "If `true`, sends Doc Detective telemetry.", + "type": "boolean", + "default": true + }, + "userId": { + "description": "Identifier for the organization, group, or individual running Doc Detective.", + "type": "string" + } + }, + "required": [ + "send" + ], + "default": { + "send": true + } + }, + "logLevel": { + "description": "Amount of detail to output when performing an operation.", + "type": "string", + "enum": [ + "silent", + "error", + "warning", + "info", + "debug" + ], + "default": "info" + } + }, + "definitions": { + "input": { + "description": "Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "recursive": { + "description": "If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specificaions and source files.", + "type": "boolean" + }, + "output": { + "description": "Path of the of the file or directory in which to store the output of Doc Detective commands. If a file path is specified, the output is written to that file. If a file of that name already exists, Doc Detective creates appends an integer to the result file name. If a directory path is specified, the output file name is dependent on the command being run.", + "type": "string", + "default": "." + }, + "markupToInclude": { + "description": "Markup types to include when performing this operation. If no markup types are specified, the operation includes all markup types as defined in `fileTypes`.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + }, + "examples": [ + {}, + { + "input": ".", + "output": "." + }, + { + "defaultCommand": "runTests", + "envVariables": "", + "input": ".", + "output": ".", + "recursive": true, + "logLevel": "info", + "runTests": { + "input": ".", + "output": ".", + "setup": "", + "cleanup": "", + "recursive": true, + "downloadDirectory": ".", + "contexts": [ + { + "app": { + "name": "firefox", + "path": "" + }, + "platforms": [ + "linux", + "mac", + "windows" + ] + } + ] + } + }, + { + "integrations": { + "openApi": [ + { + "name": "Acme", + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com", + "mockResponse": true + } + ] + } + }, + { + "envVariables": "", + "input": ".", + "output": ".", + "recursive": true, + "logLevel": "info", + "runTests": { + "input": ".", + "output": ".", + "setup": "", + "cleanup": "", + "recursive": true, + "downloadDirectory": ".", + "contexts": [ + { + "app": { + "name": "firefox", + "path": "" + }, + "platforms": [ + "linux", + "mac", + "windows" + ] + } + ] + }, + "runCoverage": { + "recursive": true, + "input": ".", + "output": ".", + "markup": [] + }, + "fileTypes": [ + { + "name": "Markdown", + "extensions": [ + ".md", + ".markdown", + ".mdx" + ], + "testStartStatementOpen": "[comment]: # (test start", + "testStartStatementClose": ")", + "testIgnoreStatement": "[comment]: # (test ignore)", + "testEndStatement": "[comment]: # (test end)", + "stepStatementOpen": "[comment]: # (step", + "stepStatementClose": ")", + "markup": [ + { + "name": "onscreenText", + "regex": [ + "\\*\\*.+?\\*\\*" + ], + "actions": [ + "find" + ] + }, + { + "name": "emphasis", + "regex": [ + "(?", + "testIgnoreStatement": "", + "testEndStatement": "", + "stepStatementOpen": "", + "markup": [] + } + ], + "integrations": {}, + "telemetry": { + "send": true, + "userId": "Doc Detective" + } + } + ] + }, + "context_v2": { + "title": "context", + "type": "object", + "description": "An application and supported platforms.\n\nIf no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For browsers, context priority is Firefox > Chrome > Chromium.", + "properties": { + "app": { + "type": "object", + "description": "The application to run.", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the application.", + "enum": [ + "chrome", + "firefox", + "safari", + "edge" + ] + }, + "path": { + "type": "string", + "description": "Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped." + }, + "options": { + "type": "object", + "description": "Options to pass to the app. Only works when `name` is `firefox` or `chrome`.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the window in pixels." + }, + "viewport_height": { + "type": "integer", + "description": "Height of the viewport in pixels. Overrides `height`." + }, + "viewport_width": { + "type": "integer", + "description": "Width of the viewport in pixels. Overrides `width`." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode. Not supported by Safari." + }, + "driverPath": { + "type": "string", + "description": "Path to the browser driver. If not specified, defaults to internally managed dependencies." + } + } + } + } + }, + "platforms": { + "description": "Supported platforms for the application.", + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + }, + "required": [ + "app", + "platforms" + ], + "additionalProperties": false, + "examples": [ + { + "app": { + "name": "chrome" + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "chrome", + "options": { + "viewport_width": 800, + "viewport_height": 600 + } + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "firefox", + "options": { + "width": 800, + "height": 600, + "headless": false, + "driverPath": "/usr/bin/geckodriver" + } + }, + "platforms": [ + "linux", + "windows", + "mac" + ] + }, + { + "app": { + "name": "safari" + }, + "platforms": [ + "mac" + ] + }, + { + "app": { + "name": "firefox", + "path": "/usr/bin/firefox" + }, + "platforms": [ + "linux" + ] + } + ] + }, + "find_v2": { + "title": "find", + "type": "object", + "description": "Check if an element exists with the specified CSS selector.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "find", + "description": "Action to perform." + }, + "selector": { + "description": "Selector that uniquely identifies the element.", + "type": "string" + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "matchText": { + "type": "string", + "description": "Text that the element should contain. If the element doesn't contain the text, the step fails. Accepts both strings an regular expressions. To use a regular expression, the expression should start and end with a `/`. For example, `/search/`." + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view. Only runs the if the test is being recorded.", + "oneOf": [ + { + "type": "boolean" + } + ], + "default": false + }, + "click": { + "description": "Click the element.", + "oneOf": [ + { + "type": "boolean", + "default": false + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + } + } + ] + }, + "typeKeys": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`typeKeys`](typeKeys). To type in the element, make the element active with the `click` parameter.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "keys": { + "description": "String of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "delay": { + "type": "number", + "description": "Delay in milliseconds between each key press. Only valid during a recording.", + "default": 100 + } + } + } + ] + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the element's text.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the element's text.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + } + }, + "required": [ + "action", + "selector" + ], + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "examples": [ + { + "action": "find", + "selector": "[title=Search]" + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": "shorthair cat" + }, + { + "action": "find", + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": { + "keys": [ + "shorthair cat" + ], + "delay": 100 + } + }, + { + "action": "find", + "selector": "[title=ResultsCount]", + "setVariables": [ + { + "name": "resultsCount", + "regex": ".*" + } + ] + } + ] + }, + "goTo_v2": { + "title": "goTo", + "type": "object", + "description": "Navigate to a specified URL.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "goTo", + "description": "Action to perform." + }, + "url": { + "type": "string", + "description": "URL to navigate to.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "url" + ], + "additionalProperties": false, + "examples": [ + { + "action": "goTo", + "url": "https://www.google.com" + }, + { + "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", + "description": "This is a test!", + "action": "goTo", + "url": "https://www.google.com" + }, + { + "id": "ddec5e20-2e81-4f38-867c-92c8d9516756", + "description": "This is a test!", + "action": "goTo", + "url": "/search", + "origin": "https://www.google.com" + } + ] + }, + "httpRequest_v2": { + "title": "httpRequest", + "type": "object", + "description": "Perform a generic HTTP request, for example to an API.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "httpRequest", + "description": "Aciton to perform." + }, + "url": { + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI definition and configuration.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI definition, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI definition." + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "requestHeaders": { + "type": "object", + "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "requestHeaders": { + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {} + }, + "responseHeaders": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {} + }, + "requestParams": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "responseParams": { + "description": "DEPRECATED.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "requestData": { + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "responseData": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in `responseData`.", + "default": true + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "envsFromResponseData": { + "description": "Environment variables to set based on response variables, as an object of the environment variable name and the jq filter applied to the response data to identify the variable's value.", + "type": "array", + "default": [], + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "jqFilter": { + "description": "jq filter to apply to the response data. If the filter doesn't return a value, the environment variable isn't set.", + "type": "string" + } + }, + "required": [ + "name", + "jqFilter" + ] + } + ] + } + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "httpRequest", + "url": "https://reqres.in/api/users" + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users/2", + "method": "put", + "requestData": { + "name": "morpheus", + "job": "zion resident" + } + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "action": "httpRequest", + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "requestHeaders": { + "header": "value" + }, + "requestParams": { + "param": "value" + }, + "requestData": { + "field": "value" + }, + "responseHeaders": { + "header": "value" + }, + "responseData": { + "field": "value" + }, + "statusCodes": [ + 200 + ] + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ], + "savePath": "response.json", + "saveDirectory": "media", + "maxVariation": 5, + "overwrite": "byVariation" + }, + { + "action": "httpRequest", + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "requestHeaders": { + "Authorization": "Bearer $TOKEN" + } + } + } + ] + }, + "moveTo_v2": { + "title": "moveTo", + "type": "object", + "description": "Move the mouse to a specific location.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "moveTo", + "description": "The action to perform." + }, + "selector": { + "description": "Selector for the element to move to.", + "type": "string" + }, + "alignment": { + "description": "Alignment of the element to move to.", + "type": "string", + "enum": [ + "top", + "bottom", + "left", + "right", + "center" + ], + "default": "center" + }, + "offset": { + "description": "Offset from the element to move to.", + "type": "object", + "properties": { + "x": { + "description": "Offset from the element to move to in x direction. Negative values move left, positive values move right.", + "type": "number", + "default": 0 + }, + "y": { + "description": "Offset from the element to move to in y direction. Negative values move up, positive values move down.", + "type": "number", + "default": 0 + } + }, + "default": {}, + "additionalProperties": false + }, + "duration": { + "description": "Duration of the move in milliseconds.", + "type": "number", + "minimum": 0, + "default": 500 + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "selector" + ], + "additionalProperties": false, + "examples": [ + { + "action": "moveTo", + "selector": "#searchInput" + }, + { + "action": "moveTo", + "selector": "#searchInput", + "alignment": "left" + }, + { + "action": "moveTo", + "selector": "#searchInput", + "alignment": "left", + "offset": { + "x": 10, + "y": 10 + } + }, + { + "action": "moveTo", + "selector": "#searchInput", + "alignment": "left", + "offset": { + "x": 10, + "y": 10 + }, + "duration": 1000 + } + ] + }, + "openApi_v2": { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI definition and configuration.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI definition, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI definition." + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "requestHeaders": { + "type": "object", + "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + } + ] + }, + "runShell_v2": { + "title": "runShell", + "type": "object", + "description": "Perform a native shell command.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "runShell", + "description": "The action to perform." + }, + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "output": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the command's output.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the command's output.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "required": [ + "action", + "command" + ], + "examples": [ + { + "action": "runShell", + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "hello-world" + ], + "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", + "description": "This is a test!" + }, + { + "action": "runShell", + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!" + }, + { + "action": "runShell", + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "output": "/.*?/", + "setVariables": [ + { + "name": "TEST", + "regex": ".*" + } + ] + }, + { + "action": "runShell", + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!", + "savePath": "docker-output.txt", + "saveDirectory": "output", + "maxVariation": 10, + "overwrite": "byVariation" + } + ] + }, + "runCode_v2": { + "title": "runCode", + "type": "object", + "description": "Assemble and run code.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "runCode", + "description": "The action to perform." + }, + "language": { + "type": "string", + "description": "Language of the code to run. If not specified, the code is run in the shell.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "type": "string", + "description": "Code to run." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "output": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the command's output.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the command's output.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "properties": { + "stdout": { + "type": "string", + "description": "Standard output of the command.", + "readOnly": true + }, + "stderr": { + "type": "string", + "description": "Standard error of the command.", + "readOnly": true + }, + "exitCode": { + "type": "integer", + "description": "Exit code of the command.", + "readOnly": true + } + } + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "required": [ + "action", + "code", + "language" + ], + "examples": [ + { + "action": "runCode", + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "action": "runCode", + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!" + }, + { + "action": "runCode", + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "action": "runCode", + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "output": "Hello from Python!", + "savePath": "python-output.txt", + "saveDirectory": "output", + "maxVariation": 10, + "overwrite": "byVariation" + } + ] + }, + "saveScreenshot_v2": { + "title": "saveScreenshot", + "type": "object", + "description": "Takes a screenshot in PNG format.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "saveScreenshot", + "description": "The action to perform." + }, + "path": { + "type": "string", + "description": "File path of the PNG file, relative to `directory`. If not specified, the file name is the ID of the step.", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)" + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the exisitng screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 5, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `byVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "crop": { + "type": "object", + "description": "Crops the screenshot.", + "properties": { + "selector": { + "type": "string", + "description": "Selector of the element to crop the image to." + }, + "padding": { + "oneOf": [ + { + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + } + } + ] + } + }, + "required": [ + "selector" + ], + "additionalProperties": false + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "saveScreenshot" + }, + { + "action": "saveScreenshot", + "path": "results.png" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "maxVariation": 10, + "overwrite": "byVariation" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element" + } + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element", + "padding": 10 + } + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element", + "padding": { + "top": 10, + "right": 20, + "bottom": 30, + "left": 40 + } + } + } + ] + }, + "setVariables_v2": { + "title": "setVariables", + "type": "object", + "description": "Load environment variables from a `.env` file.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "setVariables", + "description": "Action to perform." + }, + "path": { + "type": "string", + "description": "Path to the `.env` file." + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "path" + ], + "additionalProperties": false, + "examples": [ + { + "action": "setVariables", + "path": ".env" + } + ] + }, + "startRecording_v2": { + "title": "startRecording", + "type": "object", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecording` action. Only runs when the context `app` is `chrome` and `headless` is `false`. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "startRecording", + "description": "The action to perform." + }, + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)" + }, + "directory": { + "type": "string", + "description": "Directory of the file. Attempts to create the directory if it doesn't exist." + }, + "overwrite": { + "type": "boolean", + "description": "If `true`, overwrites the existing file at `path` if it exists.", + "default": false + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "startRecording" + }, + { + "action": "startRecording", + "path": "results.mp4" + }, + { + "action": "startRecording", + "path": "results.mp4", + "directory": "static/media", + "overwrite": true + } + ] + }, + "stopRecording_v2": { + "title": "stopRecording", + "type": "object", + "description": "Stop the current recording.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "stopRecording", + "description": "The action to perform." + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "stopRecording" + } + ] + }, + "spec_v2": { + "title": "specification", + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the test specification." + }, + "description": { + "type": "string", + "description": "Description of the test specification." + }, + "file": { + "type": "string", + "description": "Path to the file that the specification is associated with." + }, + "contexts": { + "type": "array", + "description": "Application/platform sets to run tests in. Overrides `contexts` defined at the config-level.", + "items": { + "oneOf": [ + { + "title": "context", + "type": "object", + "description": "An application and supported platforms.\n\nIf no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For browsers, context priority is Firefox > Chrome > Chromium.", + "properties": { + "app": { + "type": "object", + "description": "The application to run.", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the application.", + "enum": [ + "chrome", + "firefox", + "safari", + "edge" + ] + }, + "path": { + "type": "string", + "description": "Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped." + }, + "options": { + "type": "object", + "description": "Options to pass to the app. Only works when `name` is `firefox` or `chrome`.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the window in pixels." + }, + "viewport_height": { + "type": "integer", + "description": "Height of the viewport in pixels. Overrides `height`." + }, + "viewport_width": { + "type": "integer", + "description": "Width of the viewport in pixels. Overrides `width`." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode. Not supported by Safari." + }, + "driverPath": { + "type": "string", + "description": "Path to the browser driver. If not specified, defaults to internally managed dependencies." + } + } + } + } + }, + "platforms": { + "description": "Supported platforms for the application.", + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + }, + "required": [ + "app", + "platforms" + ], + "additionalProperties": false, + "examples": [ + { + "app": { + "name": "chrome" + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "chrome", + "options": { + "viewport_width": 800, + "viewport_height": 600 + } + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "firefox", + "options": { + "width": 800, + "height": 600, + "headless": false, + "driverPath": "/usr/bin/geckodriver" + } + }, + "platforms": [ + "linux", + "windows", + "mac" + ] + }, + { + "app": { + "name": "safari" + }, + "platforms": [ + "mac" + ] + }, + { + "app": { + "name": "firefox", + "path": "/usr/bin/firefox" + }, + "platforms": [ + "linux" + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI definition and configuration.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI definition, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI definition." + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "requestHeaders": { + "type": "object", + "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + } + ] + }, + { + "type": "object", + "properties": { + "operationId": { + "type": "null", + "$commment": "Only allow operationId at the step level." + } + }, + "required": [ + "name", + "descriptionPath" + ] + } + ] + } + }, + "tests": { + "description": "[Tests](test) to perform.", + "type": "array", + "minItems": 1, + "items": { + "oneOf": [ + { + "title": "test", + "type": "object", + "description": "A Doc Detective test.", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the test." + }, + "description": { + "type": "string", + "description": "Description of the test." + }, + "file": { + "type": "string", + "description": "Path to the file that the test is associated with." + }, + "detectSteps": { + "type": "boolean", + "description": "Whether or not to detect steps in input files based on markup regex. Defaults to `true`." + }, + "contexts": { + "type": "array", + "description": "Application/platform sets to run the test in. Overrides `contexts` defined at the config-level and spec-level.", + "items": { + "oneOf": [ + { + "title": "context", + "type": "object", + "description": "An application and supported platforms.\n\nIf no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For browsers, context priority is Firefox > Chrome > Chromium.", + "properties": { + "app": { + "type": "object", + "description": "The application to run.", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the application.", + "enum": [ + "chrome", + "firefox", + "safari", + "edge" + ] + }, + "path": { + "type": "string", + "description": "Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped." + }, + "options": { + "type": "object", + "description": "Options to pass to the app. Only works when `name` is `firefox` or `chrome`.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the window in pixels." + }, + "viewport_height": { + "type": "integer", + "description": "Height of the viewport in pixels. Overrides `height`." + }, + "viewport_width": { + "type": "integer", + "description": "Width of the viewport in pixels. Overrides `width`." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode. Not supported by Safari." + }, + "driverPath": { + "type": "string", + "description": "Path to the browser driver. If not specified, defaults to internally managed dependencies." + } + } + } + } + }, + "platforms": { + "description": "Supported platforms for the application.", + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + }, + "required": [ + "app", + "platforms" + ], + "additionalProperties": false, + "examples": [ + { + "app": { + "name": "chrome" + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "chrome", + "options": { + "viewport_width": 800, + "viewport_height": 600 + } + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "firefox", + "options": { + "width": 800, + "height": 600, + "headless": false, + "driverPath": "/usr/bin/geckodriver" + } + }, + "platforms": [ + "linux", + "windows", + "mac" + ] + }, + { + "app": { + "name": "safari" + }, + "platforms": [ + "mac" + ] + }, + { + "app": { + "name": "firefox", + "path": "/usr/bin/firefox" + }, + "platforms": [ + "linux" + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI definition and configuration.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI definition, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI definition." + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "requestHeaders": { + "type": "object", + "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + } + ] + }, + { + "type": "object", + "properties": { + "operationId": { + "type": "null", + "$commment": "Only allow operationId at the step level." + } + }, + "required": [ + "name", + "descriptionPath" + ] + } + ] + } + }, + "setup": { + "type": "string", + "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec." + }, + "cleanup": { + "type": "string", + "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec." + }, + "steps": { + "description": "Actions to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails.", + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "title": "checkLink", + "type": "object", + "description": "Check if a URL returns an acceptable status code from a GET request.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "checkLink", + "description": "Action to perform." + }, + "url": { + "type": "string", + "description": "URL to check.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201, + 202 + ] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "url" + ], + "additionalProperties": false, + "examples": [ + { + "action": "checkLink", + "url": "https://www.google.com" + }, + { + "action": "checkLink", + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + }, + { + "action": "checkLink", + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + }, + { + "title": "goTo", + "type": "object", + "description": "Navigate to a specified URL.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "goTo", + "description": "Action to perform." + }, + "url": { + "type": "string", + "description": "URL to navigate to.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "url" + ], + "additionalProperties": false, + "examples": [ + { + "action": "goTo", + "url": "https://www.google.com" + }, + { + "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", + "description": "This is a test!", + "action": "goTo", + "url": "https://www.google.com" + }, + { + "id": "ddec5e20-2e81-4f38-867c-92c8d9516756", + "description": "This is a test!", + "action": "goTo", + "url": "/search", + "origin": "https://www.google.com" + } + ] + }, + { + "title": "httpRequest", + "type": "object", + "description": "Perform a generic HTTP request, for example to an API.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "httpRequest", + "description": "Aciton to perform." + }, + "url": { + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI definition and configuration.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI definition, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI definition." + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "requestHeaders": { + "type": "object", + "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "requestHeaders": { + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {} + }, + "responseHeaders": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {} + }, + "requestParams": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "responseParams": { + "description": "DEPRECATED.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "requestData": { + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "responseData": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in `responseData`.", + "default": true + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "envsFromResponseData": { + "description": "Environment variables to set based on response variables, as an object of the environment variable name and the jq filter applied to the response data to identify the variable's value.", + "type": "array", + "default": [], + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "jqFilter": { + "description": "jq filter to apply to the response data. If the filter doesn't return a value, the environment variable isn't set.", + "type": "string" + } + }, + "required": [ + "name", + "jqFilter" + ] + } + ] + } + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "httpRequest", + "url": "https://reqres.in/api/users" + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users/2", + "method": "put", + "requestData": { + "name": "morpheus", + "job": "zion resident" + } + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "action": "httpRequest", + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "requestHeaders": { + "header": "value" + }, + "requestParams": { + "param": "value" + }, + "requestData": { + "field": "value" + }, + "responseHeaders": { + "header": "value" + }, + "responseData": { + "field": "value" + }, + "statusCodes": [ + 200 + ] + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ], + "savePath": "response.json", + "saveDirectory": "media", + "maxVariation": 5, + "overwrite": "byVariation" + }, + { + "action": "httpRequest", + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "requestHeaders": { + "Authorization": "Bearer $TOKEN" + } + } + } + ] + }, + { + "title": "runCode", + "type": "object", + "description": "Assemble and run code.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "runCode", + "description": "The action to perform." + }, + "language": { + "type": "string", + "description": "Language of the code to run. If not specified, the code is run in the shell.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "type": "string", + "description": "Code to run." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "output": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the command's output.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the command's output.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "properties": { + "stdout": { + "type": "string", + "description": "Standard output of the command.", + "readOnly": true + }, + "stderr": { + "type": "string", + "description": "Standard error of the command.", + "readOnly": true + }, + "exitCode": { + "type": "integer", + "description": "Exit code of the command.", + "readOnly": true + } + } + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "required": [ + "action", + "code", + "language" + ], + "examples": [ + { + "action": "runCode", + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "action": "runCode", + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!" + }, + { + "action": "runCode", + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "action": "runCode", + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "output": "Hello from Python!", + "savePath": "python-output.txt", + "saveDirectory": "output", + "maxVariation": 10, + "overwrite": "byVariation" + } + ] + }, + { + "title": "runShell", + "type": "object", + "description": "Perform a native shell command.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "runShell", + "description": "The action to perform." + }, + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "output": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the command's output.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the command's output.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "required": [ + "action", + "command" + ], + "examples": [ + { + "action": "runShell", + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "hello-world" + ], + "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", + "description": "This is a test!" + }, + { + "action": "runShell", + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!" + }, + { + "action": "runShell", + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "output": "/.*?/", + "setVariables": [ + { + "name": "TEST", + "regex": ".*" + } + ] + }, + { + "action": "runShell", + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!", + "savePath": "docker-output.txt", + "saveDirectory": "output", + "maxVariation": 10, + "overwrite": "byVariation" + } + ] + }, + { + "title": "saveScreenshot", + "type": "object", + "description": "Takes a screenshot in PNG format.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "saveScreenshot", + "description": "The action to perform." + }, + "path": { + "type": "string", + "description": "File path of the PNG file, relative to `directory`. If not specified, the file name is the ID of the step.", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)" + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the exisitng screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 5, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `byVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "crop": { + "type": "object", + "description": "Crops the screenshot.", + "properties": { + "selector": { + "type": "string", + "description": "Selector of the element to crop the image to." + }, + "padding": { + "oneOf": [ + { + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + } + } + ] + } + }, + "required": [ + "selector" + ], + "additionalProperties": false + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "saveScreenshot" + }, + { + "action": "saveScreenshot", + "path": "results.png" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "maxVariation": 10, + "overwrite": "byVariation" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element" + } + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element", + "padding": 10 + } + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element", + "padding": { + "top": 10, + "right": 20, + "bottom": 30, + "left": 40 + } + } + } + ] + }, + { + "title": "setVariables", + "type": "object", + "description": "Load environment variables from a `.env` file.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "setVariables", + "description": "Action to perform." + }, + "path": { + "type": "string", + "description": "Path to the `.env` file." + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "path" + ], + "additionalProperties": false, + "examples": [ + { + "action": "setVariables", + "path": ".env" + } + ] + }, + { + "title": "startRecording", + "type": "object", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecording` action. Only runs when the context `app` is `chrome` and `headless` is `false`. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "startRecording", + "description": "The action to perform." + }, + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)" + }, + "directory": { + "type": "string", + "description": "Directory of the file. Attempts to create the directory if it doesn't exist." + }, + "overwrite": { + "type": "boolean", + "description": "If `true`, overwrites the existing file at `path` if it exists.", + "default": false + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "startRecording" + }, + { + "action": "startRecording", + "path": "results.mp4" + }, + { + "action": "startRecording", + "path": "results.mp4", + "directory": "static/media", + "overwrite": true + } + ] + }, + { + "title": "stopRecording", + "type": "object", + "description": "Stop the current recording.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "stopRecording", + "description": "The action to perform." + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "stopRecording" + } + ] + }, + { + "title": "typeKeys", + "type": "object", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's enum. For example, to type the Escape key, enter `$ESCAPE$`.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "typeKeys", + "description": "The action to perform." + }, + "keys": { + "description": "String of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "delay": { + "type": "number", + "description": "Delay in milliseconds between each key press. Only valid during a recording.", + "default": 100 + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "keys" + ], + "additionalProperties": false, + "examples": [ + { + "action": "typeKeys", + "keys": "kittens" + }, + { + "action": "typeKeys", + "keys": [ + "$ENTER$" + ] + }, + { + "action": "typeKeys", + "keys": [ + "kittens", + "$ENTER$" + ], + "delay": 500 + } + ] + }, + { + "title": "find", + "type": "object", + "description": "Check if an element exists with the specified CSS selector.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "find", + "description": "Action to perform." + }, + "selector": { + "description": "Selector that uniquely identifies the element.", + "type": "string" + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "matchText": { + "type": "string", + "description": "Text that the element should contain. If the element doesn't contain the text, the step fails. Accepts both strings an regular expressions. To use a regular expression, the expression should start and end with a `/`. For example, `/search/`." + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view. Only runs the if the test is being recorded.", + "oneOf": [ + { + "type": "boolean" + } + ], + "default": false + }, + "click": { + "description": "Click the element.", + "oneOf": [ + { + "type": "boolean", + "default": false + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + } + } + ] + }, + "typeKeys": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`typeKeys`](typeKeys). To type in the element, make the element active with the `click` parameter.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "keys": { + "description": "String of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "delay": { + "type": "number", + "description": "Delay in milliseconds between each key press. Only valid during a recording.", + "default": 100 + } + } + } + ] + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the element's text.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the element's text.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + } + }, + "required": [ + "action", + "selector" + ], + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "examples": [ + { + "action": "find", + "selector": "[title=Search]" + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": "shorthair cat" + }, + { + "action": "find", + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": { + "keys": [ + "shorthair cat" + ], + "delay": 100 + } + }, + { + "action": "find", + "selector": "[title=ResultsCount]", + "setVariables": [ + { + "name": "resultsCount", + "regex": ".*" + } + ] + } + ] + }, + { + "title": "wait", + "type": "object", + "description": "Pause before performing the next action.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "wait", + "description": "The action to perform." + }, + "duration": { + "type": "number", + "description": "Milliseconds to wait.", + "default": 5000 + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "wait" + }, + { + "action": "wait", + "duration": 5000 + } + ] + } + ] + } + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "steps" + ], + "additionalProperties": false, + "examples": [ + { + "steps": [ + { + "action": "checkLink", + "url": "https://www.duckduckgo.com" + } + ] + }, + { + "steps": [ + { + "action": "goTo", + "url": "https://www.duckduckgo.com" + }, + { + "action": "find", + "selector": "[title=Search]", + "click": true, + "typeKeys": { + "keys": [ + "shorthair cats", + "$ENTER$" + ] + } + } + ] + }, + { + "id": "Do all the things! - Test", + "description": "This test includes every property across all actions.", + "contexts": [ + { + "app": { + "name": "firefox", + "path": "/usr/bin/firefox" + }, + "platforms": [ + "linux" + ] + } + ], + "setup": "setup.json", + "cleanup": "cleanup.json", + "steps": [ + { + "action": "setVariables", + "path": ".env" + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "action": "checkLink", + "url": "https://www.duckduckgo.com" + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "action": "goTo", + "url": "https://www.duckduckgo.com" + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": { + "keys": [ + "shorthair cat" + ] + } + }, + { + "action": "typeKeys", + "keys": [ + "$ENTER$" + ] + }, + { + "action": "saveScreenshot" + } + ] + }, + { + "openApi": [ + { + "name": "Acme", + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com" + } + ], + "steps": [ + { + "action": "httpRequest", + "openApi": { + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + } + ] + } + ] + } + ] + } + } + }, + "required": [ + "tests" + ], + "examples": [ + { + "tests": [ + { + "steps": [ + { + "action": "checkLink", + "url": "https://www.duckduckgo.com" + } + ] + } + ] + }, + { + "id": "Do all the things! - Spec", + "contexts": [ + { + "app": { + "name": "chrome", + "path": "/usr/bin/firefox" + }, + "platforms": [ + "windows", + "mac" + ] + } + ], + "tests": [ + { + "id": "Do all the things! - Test", + "description": "This test includes nearly every property across all actions.", + "contexts": [ + { + "app": { + "name": "firefox", + "path": "/usr/bin/firefox" + }, + "platforms": [ + "linux" + ] + } + ], + "steps": [ + { + "action": "setVariables", + "path": ".env" + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "action": "checkLink", + "url": "https://www.duckduckgo.com" + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "action": "goTo", + "url": "https://www.duckduckgo.com" + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": { + "keys": [ + "shorthair cat" + ] + } + }, + { + "action": "typeKeys", + "keys": [ + "$ENTER$" + ] + }, + { + "action": "saveScreenshot" + } + ] + } + ] + }, + { + "id": "Make a request from an OpenAPI definition", + "openApi": [ + { + "name": "Acme", + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com" + } + ], + "tests": [ + { + "steps": [ + { + "action": "httpRequest", + "openApi": { + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + } + ] + } + ] + } + ] + }, + "test_v2": { + "title": "test", + "type": "object", + "description": "A Doc Detective test.", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the test." + }, + "description": { + "type": "string", + "description": "Description of the test." + }, + "file": { + "type": "string", + "description": "Path to the file that the test is associated with." + }, + "detectSteps": { + "type": "boolean", + "description": "Whether or not to detect steps in input files based on markup regex. Defaults to `true`." + }, + "contexts": { + "type": "array", + "description": "Application/platform sets to run the test in. Overrides `contexts` defined at the config-level and spec-level.", + "items": { + "oneOf": [ + { + "title": "context", + "type": "object", + "description": "An application and supported platforms.\n\nIf no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For browsers, context priority is Firefox > Chrome > Chromium.", + "properties": { + "app": { + "type": "object", + "description": "The application to run.", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the application.", + "enum": [ + "chrome", + "firefox", + "safari", + "edge" + ] + }, + "path": { + "type": "string", + "description": "Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped." + }, + "options": { + "type": "object", + "description": "Options to pass to the app. Only works when `name` is `firefox` or `chrome`.", + "additionalProperties": false, + "properties": { + "width": { + "type": "integer", + "description": "Width of the window in pixels." + }, + "height": { + "type": "integer", + "description": "Height of the window in pixels." + }, + "viewport_height": { + "type": "integer", + "description": "Height of the viewport in pixels. Overrides `height`." + }, + "viewport_width": { + "type": "integer", + "description": "Width of the viewport in pixels. Overrides `width`." + }, + "headless": { + "type": "boolean", + "description": "If `true`, runs the browser in headless mode. Not supported by Safari." + }, + "driverPath": { + "type": "string", + "description": "Path to the browser driver. If not specified, defaults to internally managed dependencies." + } + } + } + } + }, + "platforms": { + "description": "Supported platforms for the application.", + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] + } + } + }, + "required": [ + "app", + "platforms" + ], + "additionalProperties": false, + "examples": [ + { + "app": { + "name": "chrome" + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "chrome", + "options": { + "viewport_width": 800, + "viewport_height": 600 + } + }, + "platforms": [ + "linux" + ] + }, + { + "app": { + "name": "firefox", + "options": { + "width": 800, + "height": 600, + "headless": false, + "driverPath": "/usr/bin/geckodriver" + } + }, + "platforms": [ + "linux", + "windows", + "mac" + ] + }, + { + "app": { + "name": "safari" + }, + "platforms": [ + "mac" + ] + }, + { + "app": { + "name": "firefox", + "path": "/usr/bin/firefox" + }, + "platforms": [ + "linux" + ] + } + ] + } + ] + } + }, + "openApi": { + "type": "array", + "items": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI definition and configuration.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI definition, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI definition." + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "requestHeaders": { + "type": "object", + "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + } + ] + }, + { + "type": "object", + "properties": { + "operationId": { + "type": "null", + "$commment": "Only allow operationId at the step level." + } + }, + "required": [ + "name", + "descriptionPath" + ] + } + ] + } + }, + "setup": { + "type": "string", + "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec." + }, + "cleanup": { + "type": "string", + "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec." + }, + "steps": { + "description": "Actions to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails.", + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "title": "checkLink", + "type": "object", + "description": "Check if a URL returns an acceptable status code from a GET request.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "checkLink", + "description": "Action to perform." + }, + "url": { + "type": "string", + "description": "URL to check.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200, + 201, + 202 + ] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "url" + ], + "additionalProperties": false, + "examples": [ + { + "action": "checkLink", + "url": "https://www.google.com" + }, + { + "action": "checkLink", + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + }, + { + "action": "checkLink", + "url": "/search", + "origin": "www.google.com", + "statusCodes": [ + 200 + ] + } + ] + }, + { + "title": "goTo", + "type": "object", + "description": "Navigate to a specified URL.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "goTo", + "description": "Action to perform." + }, + "url": { + "type": "string", + "description": "URL to navigate to.", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "url" + ], + "additionalProperties": false, + "examples": [ + { + "action": "goTo", + "url": "https://www.google.com" + }, + { + "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", + "description": "This is a test!", + "action": "goTo", + "url": "https://www.google.com" + }, + { + "id": "ddec5e20-2e81-4f38-867c-92c8d9516756", + "description": "This is a test!", + "action": "goTo", + "url": "/search", + "origin": "https://www.google.com" + } + ] + }, + { + "title": "httpRequest", + "type": "object", + "description": "Perform a generic HTTP request, for example to an API.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "httpRequest", + "description": "Aciton to perform." + }, + "url": { + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] + }, + "openApi": { + "allOf": [ + { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI definition and configuration.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI definition, as defined in your configuration." + }, + "descriptionPath": { + "type": "string", + "description": "URL or local path to the OpenAPI definition." + }, + "operationId": { + "type": "string", + "description": "ID of the operation to use for the request." + }, + "server": { + "type": "string", + "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition." + }, + "validateAgainstSchema": { + "type": "string", + "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "both" + }, + "mockResponse": { + "type": "boolean", + "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code." + }, + "statusCode": { + "type": "integer", + "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified." + }, + "useExample": { + "type": [ + "string" + ], + "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.", + "enum": [ + "request", + "response", + "both", + "none" + ], + "default": "none" + }, + "exampleKey": { + "type": "string", + "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.", + "default": "" + }, + "requestHeaders": { + "type": "object", + "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.", + "additionalProperties": { + "type": "string" + } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" + } + ] + }, + { + "type": "object", + "required": [ + "operationId" + ] + } + ] + }, + "statusCodes": { + "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 200 + ] + }, + "method": { + "type": "string", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], + "transform": [ + "trim", + "toEnumCase" + ], + "default": "get" + }, + "timeout": { + "type": "integer", + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 + }, + "requestHeaders": { + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {} + }, + "responseHeaders": { + "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "properties": {}, + "default": {} + }, + "requestParams": { + "description": "URL parameters to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "responseParams": { + "description": "DEPRECATED.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "requestData": { + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "responseData": { + "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "type": "object", + "additionalProperties": true, + "default": {}, + "properties": {} + }, + "allowAdditionalFields": { + "type": "boolean", + "description": "If `false`, the step fails when the response data contains fields not specified in `responseData`.", + "default": true + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "envsFromResponseData": { + "description": "Environment variables to set based on response variables, as an object of the environment variable name and the jq filter applied to the response data to identify the variable's value.", + "type": "array", + "default": [], + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "jqFilter": { + "description": "jq filter to apply to the response data. If the filter doesn't return a value, the environment variable isn't set.", + "type": "string" + } + }, + "required": [ + "name", + "jqFilter" + ] + } + ] + } + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } + ], + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "httpRequest", + "url": "https://reqres.in/api/users" + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users/2", + "method": "put", + "requestData": { + "name": "morpheus", + "job": "zion resident" + } + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "action": "httpRequest", + "url": "https://www.api-server.com", + "method": "post", + "timeout": 30000, + "requestHeaders": { + "header": "value" + }, + "requestParams": { + "param": "value" + }, + "requestData": { + "field": "value" + }, + "responseHeaders": { + "header": "value" + }, + "responseData": { + "field": "value" + }, + "statusCodes": [ + 200 + ] + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ], + "savePath": "response.json", + "saveDirectory": "media", + "maxVariation": 5, + "overwrite": "byVariation" + }, + { + "action": "httpRequest", + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + }, + { + "action": "httpRequest", + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "requestHeaders": { + "Authorization": "Bearer $TOKEN" + } + } + } + ] + }, + { + "title": "runCode", + "type": "object", + "description": "Assemble and run code.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "runCode", + "description": "The action to perform." + }, + "language": { + "type": "string", + "description": "Language of the code to run. If not specified, the code is run in the shell.", + "enum": [ + "python", + "bash", + "javascript" + ] + }, + "code": { + "type": "string", + "description": "Code to run." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "output": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the command's output.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the command's output.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + }, + "outputs": { + "type": "object", + "description": "Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence.", + "patternProperties": { + "^[A-Za-z0-9_]+$": { + "type": "string", + "description": "Runtime expression for a user-defined output value." + } + }, + "properties": { + "stdout": { + "type": "string", + "description": "Standard output of the command.", + "readOnly": true + }, + "stderr": { + "type": "string", + "description": "Standard error of the command.", + "readOnly": true + }, + "exitCode": { + "type": "integer", + "description": "Exit code of the command.", + "readOnly": true + } + } + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "required": [ + "action", + "code", + "language" + ], + "examples": [ + { + "action": "runCode", + "language": "javascript", + "code": "console.log('Hello, ${process.env.USER}!');" + }, + { + "action": "runCode", + "language": "bash", + "code": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!" + }, + { + "action": "runCode", + "language": "javascript", + "code": "return false", + "exitCodes": [ + 1 + ] + }, + { + "action": "runCode", + "language": "python", + "code": "print('Hello from Python')", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "output": "Hello from Python!", + "savePath": "python-output.txt", + "saveDirectory": "output", + "maxVariation": 10, + "overwrite": "byVariation" + } + ] + }, + { + "title": "runShell", + "type": "object", + "description": "Perform a native shell command.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "runShell", + "description": "The action to perform." + }, + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." + }, + "args": { + "type": "array", + "description": "Arguments for the command.", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + }, + "default": [] + }, + "workingDirectory": { + "type": "string", + "description": "Working directory for the command.", + "default": "." + }, + "exitCodes": { + "type": "array", + "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.", + "items": { + "oneOf": [ + { + "type": "integer" + } + ] + }, + "default": [ + 0 + ] + }, + "output": { + "type": "string", + "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`." + }, + "savePath": { + "type": "string", + "description": "File path to save the command's output, relative to `saveDirectory`." + }, + "saveDirectory": { + "type": "string", + "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory." + }, + "maxVariation": { + "type": "integer", + "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "timeout": { + "type": "integer", + "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.", + "default": 60000 + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the command's output.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the command's output.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "required": [ + "action", + "command" + ], + "examples": [ + { + "action": "runShell", + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "hello-world" + ], + "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", + "description": "This is a test!" + }, + { + "action": "runShell", + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!" + }, + { + "action": "runShell", + "command": "false", + "exitCodes": [ + 1 + ] + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "output": "/.*?/", + "setVariables": [ + { + "name": "TEST", + "regex": ".*" + } + ] + }, + { + "action": "runShell", + "command": "docker run hello-world", + "workingDirectory": ".", + "exitCodes": [ + 0 + ], + "output": "Hello from Docker!", + "savePath": "docker-output.txt", + "saveDirectory": "output", + "maxVariation": 10, + "overwrite": "byVariation" + } + ] + }, + { + "title": "saveScreenshot", + "type": "object", + "description": "Takes a screenshot in PNG format.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "saveScreenshot", + "description": "The action to perform." + }, + "path": { + "type": "string", + "description": "File path of the PNG file, relative to `directory`. If not specified, the file name is the ID of the step.", + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)" + }, + "directory": { + "type": "string", + "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory." + }, + "maxVariation": { + "type": "number", + "description": "Allowed variation in percentage of pixels between the new screenshot and the exisitng screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.", + "default": 5, + "minimum": 0, + "maximum": 100 + }, + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `byVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.", + "enum": [ + "true", + "false", + "byVariation" + ], + "default": "false" + }, + "crop": { + "type": "object", + "description": "Crops the screenshot.", + "properties": { + "selector": { + "type": "string", + "description": "Selector of the element to crop the image to." + }, + "padding": { + "oneOf": [ + { + "type": "number", + "description": "Padding in pixels to add to the bounds of the element.", + "minimum": 0 + }, + { + "type": "object", + "properties": { + "top": { + "type": "number", + "minimum": 0 + }, + "right": { + "type": "number", + "minimum": 0 + }, + "bottom": { + "type": "number", + "minimum": 0 + }, + "left": { + "type": "number", + "minimum": 0 + } + } + } + ] + } + }, + "required": [ + "selector" + ], + "additionalProperties": false + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "saveScreenshot" + }, + { + "action": "saveScreenshot", + "path": "results.png" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "maxVariation": 10, + "overwrite": "byVariation" + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element" + } + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element", + "padding": 10 + } + }, + { + "action": "saveScreenshot", + "path": "results.png", + "directory": "static/images", + "crop": { + "selector": "#element", + "padding": { + "top": 10, + "right": 20, + "bottom": 30, + "left": 40 + } + } + } + ] + }, + { + "title": "setVariables", + "type": "object", + "description": "Load environment variables from a `.env` file.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "setVariables", + "description": "Action to perform." + }, + "path": { + "type": "string", + "description": "Path to the `.env` file." + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "path" + ], + "additionalProperties": false, + "examples": [ + { + "action": "setVariables", + "path": ".env" + } + ] + }, + { + "title": "startRecording", + "type": "object", + "description": "Start recording the current browser viewport. Must be followed by a `stopRecording` action. Only runs when the context `app` is `chrome` and `headless` is `false`. Supported extensions: [ '.mp4', '.webm', '.gif' ]", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "startRecording", + "description": "The action to perform." + }, + "path": { + "type": "string", + "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.", + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)" + }, + "directory": { + "type": "string", + "description": "Directory of the file. Attempts to create the directory if it doesn't exist." + }, + "overwrite": { + "type": "boolean", + "description": "If `true`, overwrites the existing file at `path` if it exists.", + "default": false + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "startRecording" + }, + { + "action": "startRecording", + "path": "results.mp4" + }, + { + "action": "startRecording", + "path": "results.mp4", + "directory": "static/media", + "overwrite": true + } + ] + }, + { + "title": "stopRecording", + "type": "object", + "description": "Stop the current recording.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "stopRecording", + "description": "The action to perform." + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "stopRecording" + } + ] + }, + { + "title": "typeKeys", + "type": "object", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's enum. For example, to type the Escape key, enter `$ESCAPE$`.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "typeKeys", + "description": "The action to perform." + }, + "keys": { + "description": "String of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "delay": { + "type": "number", + "description": "Delay in milliseconds between each key press. Only valid during a recording.", + "default": 100 + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "keys" + ], + "additionalProperties": false, + "examples": [ + { + "action": "typeKeys", + "keys": "kittens" + }, + { + "action": "typeKeys", + "keys": [ + "$ENTER$" + ] + }, + { + "action": "typeKeys", + "keys": [ + "kittens", + "$ENTER$" + ], + "delay": 500 + } + ] + }, + { + "title": "find", + "type": "object", + "description": "Check if an element exists with the specified CSS selector.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "find", + "description": "Action to perform." + }, + "selector": { + "description": "Selector that uniquely identifies the element.", + "type": "string" + }, + "timeout": { + "type": "integer", + "description": "Max duration in milliseconds to wait for the element to exist.", + "default": 5000 + }, + "matchText": { + "type": "string", + "description": "Text that the element should contain. If the element doesn't contain the text, the step fails. Accepts both strings an regular expressions. To use a regular expression, the expression should start and end with a `/`. For example, `/search/`." + }, + "moveTo": { + "description": "Move to the element. If the element isn't visible, it's scrolled into view. Only runs the if the test is being recorded.", + "oneOf": [ + { + "type": "boolean" + } + ], + "default": false + }, + "click": { + "description": "Click the element.", + "oneOf": [ + { + "type": "boolean", + "default": false + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "button": { + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] + } + } + } + ] + }, + "typeKeys": { + "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`typeKeys`](typeKeys). To type in the element, make the element active with the `click` parameter.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "keys": { + "description": "String of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "delay": { + "type": "number", + "description": "Delay in milliseconds between each key press. Only valid during a recording.", + "default": 100 + } + } + } + ] + }, + "setVariables": { + "type": "array", + "description": "Extract environment variables from the element's text.", + "items": { + "oneOf": [ + { + "description": "", + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable to set.", + "type": "string" + }, + "regex": { + "description": "Regex to extract the environment variable from the element's text.", + "type": "string" + } + }, + "required": [ + "name", + "regex" + ] + } + ] + }, + "default": [] + } + }, + "required": [ + "action", + "selector" + ], + "dynamicDefaults": { + "id": "uuid" + }, + "additionalProperties": false, + "examples": [ + { + "action": "find", + "selector": "[title=Search]" + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": "shorthair cat" + }, + { + "action": "find", + "selector": "[title=Search]", + "click": { + "button": "right" + } + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": { + "keys": [ + "shorthair cat" + ], + "delay": 100 + } + }, + { + "action": "find", + "selector": "[title=ResultsCount]", + "setVariables": [ + { + "name": "resultsCount", + "regex": ".*" + } + ] + } + ] + }, + { + "title": "wait", + "type": "object", + "description": "Pause before performing the next action.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "wait", + "description": "The action to perform." + }, + "duration": { + "type": "number", + "description": "Milliseconds to wait.", + "default": 5000 + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "wait" + }, + { + "action": "wait", + "duration": 5000 + } + ] + } + ] + } + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "steps" + ], + "additionalProperties": false, + "examples": [ + { + "steps": [ + { + "action": "checkLink", + "url": "https://www.duckduckgo.com" + } + ] + }, + { + "steps": [ + { + "action": "goTo", + "url": "https://www.duckduckgo.com" + }, + { + "action": "find", + "selector": "[title=Search]", + "click": true, + "typeKeys": { + "keys": [ + "shorthair cats", + "$ENTER$" + ] + } + } + ] + }, + { + "id": "Do all the things! - Test", + "description": "This test includes every property across all actions.", + "contexts": [ + { + "app": { + "name": "firefox", + "path": "/usr/bin/firefox" + }, + "platforms": [ + "linux" + ] + } + ], + "setup": "setup.json", + "cleanup": "cleanup.json", + "steps": [ + { + "action": "setVariables", + "path": ".env" + }, + { + "action": "runShell", + "command": "echo", + "args": [ + "$USER" + ] + }, + { + "action": "checkLink", + "url": "https://www.duckduckgo.com" + }, + { + "action": "httpRequest", + "url": "https://reqres.in/api/users", + "method": "post", + "requestData": { + "name": "morpheus", + "job": "leader" + }, + "responseData": { + "name": "morpheus", + "job": "leader" + }, + "statusCodes": [ + 200, + 201 + ] + }, + { + "action": "goTo", + "url": "https://www.duckduckgo.com" + }, + { + "action": "find", + "selector": "[title=Search]", + "timeout": 10000, + "matchText": "Search", + "moveTo": true, + "click": true, + "typeKeys": { + "keys": [ + "shorthair cat" + ] + } + }, + { + "action": "typeKeys", + "keys": [ + "$ENTER$" + ] + }, + { + "action": "saveScreenshot" + } + ] + }, + { + "openApi": [ + { + "name": "Acme", + "descriptionPath": "https://www.acme.com/openapi.json", + "server": "https://api.acme.com" + } + ], + "steps": [ + { + "action": "httpRequest", + "openApi": { + "operationId": "getUserById" + }, + "requestParams": { + "id": 123 + } + } + ] + } + ] + }, + "typeKeys_v2": { + "title": "typeKeys", + "type": "object", + "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's enum. For example, to type the Escape key, enter `$ESCAPE$`.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "typeKeys", + "description": "The action to perform." + }, + "keys": { + "description": "String of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + } + ] + } + } + ] + }, + "delay": { + "type": "number", + "description": "Delay in milliseconds between each key press. Only valid during a recording.", + "default": 100 + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action", + "keys" + ], + "additionalProperties": false, + "examples": [ + { + "action": "typeKeys", + "keys": "kittens" + }, + { + "action": "typeKeys", + "keys": [ + "$ENTER$" + ] + }, + { + "action": "typeKeys", + "keys": [ + "kittens", + "$ENTER$" + ], + "delay": 500 + } + ] + }, + "wait_v2": { + "title": "wait", + "type": "object", + "description": "Pause before performing the next action.", + "properties": { + "id": { + "type": "string", + "description": "ID of the step." + }, + "description": { + "type": "string", + "description": "Description of the step." + }, + "action": { + "type": "string", + "const": "wait", + "description": "The action to perform." + }, + "duration": { + "type": "number", + "description": "Milliseconds to wait.", + "default": 5000 + } + }, + "dynamicDefaults": { + "id": "uuid" + }, + "required": [ + "action" + ], + "additionalProperties": false, + "examples": [ + { + "action": "wait" + }, + { + "action": "wait", + "duration": 5000 + } + ] + } +} diff --git a/dist/types/generated/checkLink_v3.d.ts b/dist/types/generated/checkLink_v3.d.ts new file mode 100644 index 00000000..a7888382 --- /dev/null +++ b/dist/types/generated/checkLink_v3.d.ts @@ -0,0 +1,27 @@ +/** + * Auto-generated from checkLink_v3.schema.json + * Do not edit manually + */ +export type CheckLink = CheckLinkDetailed | CheckLinkDetailed1; +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export type CheckLinkDetailed = string; +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export interface CheckLinkDetailed1 { + /** + * URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. + */ + statusCodes?: number | number[]; +} +//# sourceMappingURL=checkLink_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/checkLink_v3.d.ts.map b/dist/types/generated/checkLink_v3.d.ts.map new file mode 100644 index 00000000..402b0654 --- /dev/null +++ b/dist/types/generated/checkLink_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"checkLink_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/checkLink_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAC/D;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACjC"} \ No newline at end of file diff --git a/dist/types/generated/checkLink_v3.js b/dist/types/generated/checkLink_v3.js new file mode 100644 index 00000000..af7927d6 --- /dev/null +++ b/dist/types/generated/checkLink_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from checkLink_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=checkLink_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/checkLink_v3.js.map b/dist/types/generated/checkLink_v3.js.map new file mode 100644 index 00000000..3af782d0 --- /dev/null +++ b/dist/types/generated/checkLink_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"checkLink_v3.js","sourceRoot":"","sources":["../../../src/types/generated/checkLink_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/click_v3.d.ts b/dist/types/generated/click_v3.d.ts new file mode 100644 index 00000000..f0e520f2 --- /dev/null +++ b/dist/types/generated/click_v3.d.ts @@ -0,0 +1,16 @@ +/** + * Auto-generated from click_v3.schema.json + * Do not edit manually + */ +/** + * Click or tap an element. + */ +export type Click = ClickElementSimple | ClickElementDetailed | boolean; +/** + * Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type ClickElementSimple = string; +export type ClickElementDetailed = { + [k: string]: unknown; +}; +//# sourceMappingURL=click_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/click_v3.d.ts.map b/dist/types/generated/click_v3.d.ts.map new file mode 100644 index 00000000..6406f29d --- /dev/null +++ b/dist/types/generated/click_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"click_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/click_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,kBAAkB,GAAG,oBAAoB,GAAG,OAAO,CAAC;AACxE;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACxC,MAAM,MAAM,oBAAoB,GAAG;IACjC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC"} \ No newline at end of file diff --git a/dist/types/generated/click_v3.js b/dist/types/generated/click_v3.js new file mode 100644 index 00000000..e91b65b4 --- /dev/null +++ b/dist/types/generated/click_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from click_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=click_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/click_v3.js.map b/dist/types/generated/click_v3.js.map new file mode 100644 index 00000000..d878a37f --- /dev/null +++ b/dist/types/generated/click_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"click_v3.js","sourceRoot":"","sources":["../../../src/types/generated/click_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/config_v3.d.ts b/dist/types/generated/config_v3.d.ts new file mode 100644 index 00000000..73f006f6 --- /dev/null +++ b/dist/types/generated/config_v3.d.ts @@ -0,0 +1,398 @@ +/** + * Auto-generated from config_v3.schema.json + * Do not edit manually + */ +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables = string; +export type FileTypePredefined = "markdown" | "asciidoc" | "html" | "dita"; +export type FileTypeCustom = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Perform a native shell command. + */ +export type RunShell = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +}; +/** + * Configuration for Heretto CMS integrations. Each entry specifies a Heretto instance and a scenario to build and test. + */ +export type HerettoCMSIntegrations = HerettoCMSIntegration[]; +/** + * Configuration options for Doc Detective operations. + */ +export interface Config { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/config_v3.schema.json"; + /** + * Identifier for the configuration. + */ + configId?: string; + /** + * Path to the configuration file. + */ + configPath?: string; + /** + * Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files. + */ + input?: string | [string, ...string[]]; + /** + * Path of the directory in which to store the output of Doc Detective commands. If a file path is specified, Doc Detective attempts to honor the file name specified, but file path behavior is controlled by the configured reporters. + */ + output?: string; + /** + * If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specifications and source files. + */ + recursive?: boolean; + /** + * Whether paths should be interpreted as relative to the current working directory (`cwd`) or to the file in which they're specified (`file`). + */ + relativePathBase?: "cwd" | "file"; + loadVariables?: LoadVariables; + /** + * Default protocol and domain to use for relative URLs. + */ + origin?: string; + /** + * Path(s) to test specifications to perform before those specified by `input`. Useful for setting up testing environments. + */ + beforeAny?: string | string[]; + /** + * Path(s) to test specifications to perform after those specified by `input`. Useful for cleaning up testing environments. + */ + afterAll?: string | string[]; + /** + * Whether or not to detect steps in input files based on defined markup. + */ + detectSteps?: boolean; + /** + * Whether or not to run potentially unsafe steps, such as those that might modify files or system state. + */ + allowUnsafeSteps?: boolean; + /** + * If `true`, crawls sitemap.xml files specified by URL to find additional files to test. + */ + crawl?: boolean; + /** + * If `true`, processes DITA maps and includes generated files as inputs. + */ + processDitaMaps?: boolean; + /** + * Amount of detail to output when performing an operation. + */ + logLevel?: "silent" | "error" | "warning" | "info" | "debug"; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + /** + * Configuration for file types and their markup detection. + */ + fileTypes?: [ + FileTypePredefined | FileTypeCustom | FileTypeExecutable, + ...(FileTypePredefined | FileTypeCustom | FileTypeExecutable)[] + ]; + integrations?: IntegrationsOptions; + telemetry?: TelemetryOptions; + /** + * Number of concurrent test runners. Set to true to use CPU core count (capped at 4). + */ + concurrentRunners?: number | boolean; + environment?: EnvironmentDetails; + /** + * Enable debugging mode. `true` allows pausing on breakpoints, waiting for user input before continuing. `stepThrough` pauses at every step, waiting for user input before continuing. `false` disables all debugging. + */ + debug?: boolean | "stepThrough"; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: ("chrome" | "firefox" | "safari" | "webkit") | Browser | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface FileTypeExecutable { + /** + * File extensions to use with type. + */ + extensions: string | [string, ...string[]]; + /** + * `runShell` step to perform for this file type. Use $1 as a placeholder for the file path. + */ + runShell?: RunShell; + [k: string]: unknown; +} +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +/** + * Options for connecting to external services. + */ +export interface IntegrationsOptions { + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + docDetectiveApi?: DocDetectiveOrchestrationAPI; + heretto?: HerettoCMSIntegrations; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} +/** + * Configuration for Doc Detective Orchestration API integration. + */ +export interface DocDetectiveOrchestrationAPI { + /** + * API key for authenticating with the Doc Detective Orchestration API. + */ + apiKey?: string; +} +export interface HerettoCMSIntegration { + /** + * Unique identifier for this Heretto integration. Used in logs and results. + */ + name: string; + /** + * The organization subdomain used to access Heretto CCMS (e.g., 'thunderbird' for thunderbird.heretto.com). + */ + organizationId: string; + /** + * Heretto CCMS username (email address) for API authentication. + */ + username: string; + /** + * API token generated in Heretto CCMS for authentication. See https://help.heretto.com/en/heretto-ccms/api/ccms-api-authentication/basic-authentication#ariaid-title3 + */ + apiToken: string; + /** + * Name of the scenario to build and test. + */ + scenarioName?: string; + /** + * Local path where Heretto content was downloaded. Set automatically during processing. + */ + outputPath?: string; + /** + * Mapping of local file paths to Heretto file metadata. Set automatically during content loading. + */ + fileMapping?: { + [k: string]: { + /** + * The UUID of the file in Heretto. + */ + fileId?: string; + /** + * The path of the file in Heretto. + */ + filePath?: string; + [k: string]: unknown; + }; + }; + /** + * If `true`, uploads changed screenshots and other media files back to Heretto CMS after test execution. + */ + uploadOnChange?: boolean; + /** + * Mapping of Heretto file paths to their UUIDs and metadata. Set automatically during content loading by fetching ditamap resource dependencies. + */ + resourceDependencies?: { + [k: string]: { + /** + * The UUID of the file in Heretto. + */ + uuid?: string; + /** + * The full xmldb path of the file in Heretto. + */ + fullPath?: string; + /** + * The file name. + */ + name?: string; + /** + * The UUID of the parent folder in Heretto. + */ + parentFolderId?: string; + [k: string]: unknown; + }; + }; +} +/** + * Options around sending telemetry for Doc Detective usage. + */ +export interface TelemetryOptions { + /** + * If `true`, sends Doc Detective telemetry. + */ + send: boolean; + /** + * Identifier for the organization, group, or individual running Doc Detective. + */ + userId?: string; +} +/** + * Environment information for the system running Doc Detective. + */ +export interface EnvironmentDetails { + /** + * The current working directory of the process running Doc Detective. + */ + workingDirectory?: string; + /** + * The operating system type running Doc Detective. + */ + platform: "linux" | "mac" | "windows"; + /** + * The processor architecture of the system running Doc Detective. + */ + arch?: "arm32" | "arm64" | "x32" | "x64"; +} +//# sourceMappingURL=config_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/config_v3.d.ts.map b/dist/types/generated/config_v3.d.ts.map new file mode 100644 index 00000000..90c5bda7 --- /dev/null +++ b/dist/types/generated/config_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"config_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/config_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AACnC,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAC3E,MAAM,MAAM,cAAc,GACtB;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,qBAAqB,GAAG,uBAAuB,CAAC;AACvE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC3C;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,EAAE,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB;;OAEG;IACH,OAAO,CAAC,EAAE,2GAA2G,CAAC;IACtH;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IACvC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAClC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7D;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE;QACV,kBAAkB,GAAG,cAAc,GAAG,kBAAkB;QACxD,GAAG,CAAC,kBAAkB,GAAG,cAAc,GAAG,kBAAkB,CAAC,EAAE;KAChE,CAAC;IACF,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACrC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;CACjC;AACD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,4GAA4G,CAAC;IACvH;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC,EAAE,CAAC;IAC5E;;OAEG;IACH,QAAQ,CAAC,EACL,CAAC,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAC5C,OAAO,GACP,CAAC,CAAC,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;CACjE;AACD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,UAAU,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,CAAC,OAAO,GAAG,sBAAsB,CAAC,EAAE,CAAC;IAC/C,eAAe,CAAC,EAAE,4BAA4B,CAAC;IAC/C,OAAO,CAAC,EAAE,sBAAsB,CAAC;CAClC;AACD,MAAM,WAAW,sBAAsB;IACrC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,WAAW,CAAC,EAAE;QACZ,CAAC,CAAC,EAAE,MAAM,GAAG;YACX;;eAEG;YACH,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB;;eAEG;YACH,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,CAAC;KACH,CAAC;IACF;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;OAEG;IACH,oBAAoB,CAAC,EAAE;QACrB,CAAC,CAAC,EAAE,MAAM,GAAG;YACX;;eAEG;YACH,IAAI,CAAC,EAAE,MAAM,CAAC;YACd;;eAEG;YACH,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB;;eAEG;YACH,IAAI,CAAC,EAAE,MAAM,CAAC;YACd;;eAEG;YACH,cAAc,CAAC,EAAE,MAAM,CAAC;YACxB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,CAAC;KACH,CAAC;CACH;AACD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,QAAQ,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC;IACtC;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,CAAC;CAC1C"} \ No newline at end of file diff --git a/dist/types/generated/config_v3.js b/dist/types/generated/config_v3.js new file mode 100644 index 00000000..8cd0ed27 --- /dev/null +++ b/dist/types/generated/config_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from config_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=config_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/config_v3.js.map b/dist/types/generated/config_v3.js.map new file mode 100644 index 00000000..4e8308cf --- /dev/null +++ b/dist/types/generated/config_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"config_v3.js","sourceRoot":"","sources":["../../../src/types/generated/config_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/context_v3.d.ts b/dist/types/generated/context_v3.d.ts new file mode 100644 index 00000000..1db454e6 --- /dev/null +++ b/dist/types/generated/context_v3.d.ts @@ -0,0 +1,108 @@ +/** + * Auto-generated from context_v3.schema.json + * Do not edit manually + */ +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: ("chrome" | "firefox" | "safari" | "webkit") | Browser | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +//# sourceMappingURL=context_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/context_v3.d.ts.map b/dist/types/generated/context_v3.d.ts.map new file mode 100644 index 00000000..1416330b --- /dev/null +++ b/dist/types/generated/context_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"context_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/context_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,4GAA4G,CAAC;IACvH;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC,EAAE,CAAC;IAC5E;;OAEG;IACH,QAAQ,CAAC,EACL,CAAC,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAC5C,OAAO,GACP,CAAC,CAAC,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;CACjE;AACD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"} \ No newline at end of file diff --git a/dist/types/generated/context_v3.js b/dist/types/generated/context_v3.js new file mode 100644 index 00000000..39feaeda --- /dev/null +++ b/dist/types/generated/context_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from context_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=context_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/context_v3.js.map b/dist/types/generated/context_v3.js.map new file mode 100644 index 00000000..a593df9a --- /dev/null +++ b/dist/types/generated/context_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"context_v3.js","sourceRoot":"","sources":["../../../src/types/generated/context_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/dragAndDrop_v3.d.ts b/dist/types/generated/dragAndDrop_v3.d.ts new file mode 100644 index 00000000..0a66af13 --- /dev/null +++ b/dist/types/generated/dragAndDrop_v3.d.ts @@ -0,0 +1,37 @@ +/** + * Auto-generated from dragAndDrop_v3.schema.json + * Do not edit manually + */ +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple = string; +export type ElementDetailed = { + [k: string]: unknown; +}; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple1 = string; +export type ElementDetailed1 = { + [k: string]: unknown; +}; +/** + * Drag and drop an element from source to target. + */ +export interface DragAndDrop { + /** + * The element to drag. + */ + source: ElementSimple | ElementDetailed; + /** + * The target location to drop the element. + */ + target: ElementSimple1 | ElementDetailed1; + /** + * Duration of the drag operation in milliseconds. + */ + duration?: number; + [k: string]: unknown; +} +//# sourceMappingURL=dragAndDrop_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/dragAndDrop_v3.d.ts.map b/dist/types/generated/dragAndDrop_v3.d.ts.map new file mode 100644 index 00000000..fbf1692e --- /dev/null +++ b/dist/types/generated/dragAndDrop_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"dragAndDrop_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/dragAndDrop_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AACnC,MAAM,MAAM,eAAe,GAAG;IAC5B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AACpC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,MAAM,EAAE,aAAa,GAAG,eAAe,CAAC;IACxC;;OAEG;IACH,MAAM,EAAE,cAAc,GAAG,gBAAgB,CAAC;IAC1C;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB"} \ No newline at end of file diff --git a/dist/types/generated/dragAndDrop_v3.js b/dist/types/generated/dragAndDrop_v3.js new file mode 100644 index 00000000..5fb2a52f --- /dev/null +++ b/dist/types/generated/dragAndDrop_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from dragAndDrop_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=dragAndDrop_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/dragAndDrop_v3.js.map b/dist/types/generated/dragAndDrop_v3.js.map new file mode 100644 index 00000000..8cef45b6 --- /dev/null +++ b/dist/types/generated/dragAndDrop_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dragAndDrop_v3.js","sourceRoot":"","sources":["../../../src/types/generated/dragAndDrop_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/endRecord_v3.d.ts b/dist/types/generated/endRecord_v3.d.ts new file mode 100644 index 00000000..cfa42e98 --- /dev/null +++ b/dist/types/generated/endRecord_v3.d.ts @@ -0,0 +1,9 @@ +/** + * Auto-generated from endRecord_v3.schema.json + * Do not edit manually + */ +/** + * Stop the current recording. + */ +export type EndRecord = boolean; +//# sourceMappingURL=endRecord_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/endRecord_v3.d.ts.map b/dist/types/generated/endRecord_v3.d.ts.map new file mode 100644 index 00000000..c2063ec0 --- /dev/null +++ b/dist/types/generated/endRecord_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"endRecord_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/endRecord_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC"} \ No newline at end of file diff --git a/dist/types/generated/endRecord_v3.js b/dist/types/generated/endRecord_v3.js new file mode 100644 index 00000000..3798788a --- /dev/null +++ b/dist/types/generated/endRecord_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from endRecord_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=endRecord_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/endRecord_v3.js.map b/dist/types/generated/endRecord_v3.js.map new file mode 100644 index 00000000..6861b0d1 --- /dev/null +++ b/dist/types/generated/endRecord_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"endRecord_v3.js","sourceRoot":"","sources":["../../../src/types/generated/endRecord_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/find_v3.d.ts b/dist/types/generated/find_v3.d.ts new file mode 100644 index 00000000..7e73f9a0 --- /dev/null +++ b/dist/types/generated/find_v3.d.ts @@ -0,0 +1,16 @@ +/** + * Auto-generated from find_v3.schema.json + * Do not edit manually + */ +/** + * Find an element based on display text or a selector, then optionally interact with it. + */ +export type Find = FindElementSimple | FindElementDetailed; +/** + * Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type FindElementSimple = string; +export type FindElementDetailed = { + [k: string]: unknown; +}; +//# sourceMappingURL=find_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/find_v3.d.ts.map b/dist/types/generated/find_v3.d.ts.map new file mode 100644 index 00000000..93f94b52 --- /dev/null +++ b/dist/types/generated/find_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"find_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/find_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAC3D;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC,MAAM,MAAM,mBAAmB,GAAG;IAChC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC"} \ No newline at end of file diff --git a/dist/types/generated/find_v3.js b/dist/types/generated/find_v3.js new file mode 100644 index 00000000..82e9dc14 --- /dev/null +++ b/dist/types/generated/find_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from find_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=find_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/find_v3.js.map b/dist/types/generated/find_v3.js.map new file mode 100644 index 00000000..857ed32d --- /dev/null +++ b/dist/types/generated/find_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"find_v3.js","sourceRoot":"","sources":["../../../src/types/generated/find_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/goTo_v3.d.ts b/dist/types/generated/goTo_v3.d.ts new file mode 100644 index 00000000..1d3a8f09 --- /dev/null +++ b/dist/types/generated/goTo_v3.d.ts @@ -0,0 +1,46 @@ +/** + * Auto-generated from goTo_v3.schema.json + * Do not edit manually + */ +export type GoTo = GoToURLSimple | GoToURLDetailed; +/** + * Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any. + */ +export type GoToURLSimple = string; +/** + * Navigate to an HTTP or HTTPS URL. + */ +export interface GoToURLDetailed { + /** + * URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails. + */ + timeout?: number; + /** + * Configuration for waiting conditions after navigation. + */ + waitUntil?: { + /** + * Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check. + */ + networkIdleTime?: number | null; + /** + * Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check. + */ + domIdleTime?: number | null; + /** + * Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified. + */ + find?: { + [k: string]: unknown; + }; + }; +} +//# sourceMappingURL=goTo_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/goTo_v3.d.ts.map b/dist/types/generated/goTo_v3.d.ts.map new file mode 100644 index 00000000..284f6217 --- /dev/null +++ b/dist/types/generated/goTo_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"goTo_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/goTo_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH,MAAM,MAAM,IAAI,GAAG,aAAa,GAAG,eAAe,CAAC;AACnD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AAEnC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,SAAS,CAAC,EAAE;QACV;;WAEG;QACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B;;WAEG;QACH,IAAI,CAAC,EAAE;YACL,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,CAAC;KACH,CAAC;CACH"} \ No newline at end of file diff --git a/dist/types/generated/goTo_v3.js b/dist/types/generated/goTo_v3.js new file mode 100644 index 00000000..45a3393d --- /dev/null +++ b/dist/types/generated/goTo_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from goTo_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=goTo_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/goTo_v3.js.map b/dist/types/generated/goTo_v3.js.map new file mode 100644 index 00000000..80f590a6 --- /dev/null +++ b/dist/types/generated/goTo_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"goTo_v3.js","sourceRoot":"","sources":["../../../src/types/generated/goTo_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/httpRequest_v3.d.ts b/dist/types/generated/httpRequest_v3.d.ts new file mode 100644 index 00000000..143a9764 --- /dev/null +++ b/dist/types/generated/httpRequest_v3.d.ts @@ -0,0 +1,16 @@ +/** + * Auto-generated from httpRequest_v3.schema.json + * Do not edit manually + */ +/** + * Perform a generic HTTP request, for example to an API. + */ +export type HttpRequest = HTTPRequestSimple | HTTPRequestDetailed; +/** + * URL for the HTTP request. + */ +export type HTTPRequestSimple = string; +export type HTTPRequestDetailed = { + [k: string]: unknown; +}; +//# sourceMappingURL=httpRequest_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/httpRequest_v3.d.ts.map b/dist/types/generated/httpRequest_v3.d.ts.map new file mode 100644 index 00000000..03fe0ace --- /dev/null +++ b/dist/types/generated/httpRequest_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"httpRequest_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/httpRequest_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAClE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC,MAAM,MAAM,mBAAmB,GAAG;IAChC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC"} \ No newline at end of file diff --git a/dist/types/generated/httpRequest_v3.js b/dist/types/generated/httpRequest_v3.js new file mode 100644 index 00000000..eaf0d7c5 --- /dev/null +++ b/dist/types/generated/httpRequest_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from httpRequest_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=httpRequest_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/httpRequest_v3.js.map b/dist/types/generated/httpRequest_v3.js.map new file mode 100644 index 00000000..37d7cf93 --- /dev/null +++ b/dist/types/generated/httpRequest_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"httpRequest_v3.js","sourceRoot":"","sources":["../../../src/types/generated/httpRequest_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/loadCookie_v3.d.ts b/dist/types/generated/loadCookie_v3.d.ts new file mode 100644 index 00000000..807dc483 --- /dev/null +++ b/dist/types/generated/loadCookie_v3.d.ts @@ -0,0 +1,16 @@ +/** + * Auto-generated from loadCookie_v3.schema.json + * Do not edit manually + */ +/** + * Load a specific cookie from a file or environment variable into the browser. + */ +export type LoadCookie = CookieNameOrFilePath | LoadCookieDetailed; +/** + * Name of the specific cookie to load from default location, or file path to cookie file. + */ +export type CookieNameOrFilePath = string; +export type LoadCookieDetailed = { + [k: string]: unknown; +}; +//# sourceMappingURL=loadCookie_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/loadCookie_v3.d.ts.map b/dist/types/generated/loadCookie_v3.d.ts.map new file mode 100644 index 00000000..ce457e90 --- /dev/null +++ b/dist/types/generated/loadCookie_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"loadCookie_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/loadCookie_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AACnE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC1C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC"} \ No newline at end of file diff --git a/dist/types/generated/loadCookie_v3.js b/dist/types/generated/loadCookie_v3.js new file mode 100644 index 00000000..39480269 --- /dev/null +++ b/dist/types/generated/loadCookie_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from loadCookie_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=loadCookie_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/loadCookie_v3.js.map b/dist/types/generated/loadCookie_v3.js.map new file mode 100644 index 00000000..8b0c0780 --- /dev/null +++ b/dist/types/generated/loadCookie_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"loadCookie_v3.js","sourceRoot":"","sources":["../../../src/types/generated/loadCookie_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/loadVariables_v3.d.ts b/dist/types/generated/loadVariables_v3.d.ts new file mode 100644 index 00000000..d75ff1cf --- /dev/null +++ b/dist/types/generated/loadVariables_v3.d.ts @@ -0,0 +1,9 @@ +/** + * Auto-generated from loadVariables_v3.schema.json + * Do not edit manually + */ +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables = string; +//# sourceMappingURL=loadVariables_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/loadVariables_v3.d.ts.map b/dist/types/generated/loadVariables_v3.d.ts.map new file mode 100644 index 00000000..7d025996 --- /dev/null +++ b/dist/types/generated/loadVariables_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"loadVariables_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/loadVariables_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC"} \ No newline at end of file diff --git a/dist/types/generated/loadVariables_v3.js b/dist/types/generated/loadVariables_v3.js new file mode 100644 index 00000000..cc6f98a9 --- /dev/null +++ b/dist/types/generated/loadVariables_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from loadVariables_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=loadVariables_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/loadVariables_v3.js.map b/dist/types/generated/loadVariables_v3.js.map new file mode 100644 index 00000000..79ffdf89 --- /dev/null +++ b/dist/types/generated/loadVariables_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"loadVariables_v3.js","sourceRoot":"","sources":["../../../src/types/generated/loadVariables_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/openApi_v3.d.ts b/dist/types/generated/openApi_v3.d.ts new file mode 100644 index 00000000..a06201fe --- /dev/null +++ b/dist/types/generated/openApi_v3.d.ts @@ -0,0 +1,62 @@ +/** + * Auto-generated from openApi_v3.schema.json + * Do not edit manually + */ +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +} & { + /** + * Name of the OpenAPI description, as defined in your configuration. + */ + name?: string; + /** + * URL or local path to the OpenAPI description. + */ + descriptionPath?: string; + definition?: OpenAPIDefinition; + /** + * ID of the operation to use for the request. + */ + operationId?: string; + /** + * Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description. + */ + server?: string; + /** + * Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails. + */ + validateAgainstSchema?: "request" | "response" | "both" | "none"; + /** + * If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code. + */ + mockResponse?: boolean; + /** + * Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified. + */ + statusCode?: number; + /** + * Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified. + */ + useExample?: "request" | "response" | "both" | "none"; + /** + * Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used. + */ + exampleKey?: string; + headers?: OpenAPIRequestHeaders; +}; +/** + * OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined. + */ +export interface OpenAPIDefinition { + [k: string]: unknown; +} +/** + * Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value. + */ +export interface OpenAPIRequestHeaders { + [k: string]: string; +} +//# sourceMappingURL=openApi_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/openApi_v3.d.ts.map b/dist/types/generated/openApi_v3.d.ts.map new file mode 100644 index 00000000..19994875 --- /dev/null +++ b/dist/types/generated/openApi_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"openApi_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/openApi_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GAAG;IACF;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,qBAAqB,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;IACjE;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,UAAU,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;IACtD;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB"} \ No newline at end of file diff --git a/dist/types/generated/openApi_v3.js b/dist/types/generated/openApi_v3.js new file mode 100644 index 00000000..7a692a77 --- /dev/null +++ b/dist/types/generated/openApi_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from openApi_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=openApi_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/openApi_v3.js.map b/dist/types/generated/openApi_v3.js.map new file mode 100644 index 00000000..b2c48afb --- /dev/null +++ b/dist/types/generated/openApi_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openApi_v3.js","sourceRoot":"","sources":["../../../src/types/generated/openApi_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/record_v3.d.ts b/dist/types/generated/record_v3.d.ts new file mode 100644 index 00000000..15b8ef4d --- /dev/null +++ b/dist/types/generated/record_v3.d.ts @@ -0,0 +1,32 @@ +/** + * Auto-generated from record_v3.schema.json + * Do not edit manually + */ +/** + * Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ] + */ +export type Record = RecordSimple | RecordDetailed | RecordBoolean; +/** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ +export type RecordSimple = string; +/** + * If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport. + */ +export type RecordBoolean = boolean; +export interface RecordDetailed { + /** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ + path?: string; + /** + * Directory of the file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * If `true`, overwrites the existing recording at `path` if it exists. + */ + overwrite?: "true" | "false"; + [k: string]: unknown; +} +//# sourceMappingURL=record_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/record_v3.d.ts.map b/dist/types/generated/record_v3.d.ts.map new file mode 100644 index 00000000..f4f8c6fa --- /dev/null +++ b/dist/types/generated/record_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"record_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/record_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,cAAc,GAAG,aAAa,CAAC;AACnE;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;AAEpC,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB"} \ No newline at end of file diff --git a/dist/types/generated/record_v3.js b/dist/types/generated/record_v3.js new file mode 100644 index 00000000..6ae0b9d4 --- /dev/null +++ b/dist/types/generated/record_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from record_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=record_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/record_v3.js.map b/dist/types/generated/record_v3.js.map new file mode 100644 index 00000000..d20811a9 --- /dev/null +++ b/dist/types/generated/record_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"record_v3.js","sourceRoot":"","sources":["../../../src/types/generated/record_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/report_v3.d.ts b/dist/types/generated/report_v3.d.ts new file mode 100644 index 00000000..deecfe7a --- /dev/null +++ b/dist/types/generated/report_v3.d.ts @@ -0,0 +1,174 @@ +/** + * Auto-generated from report_v3.schema.json + * Do not edit manually + */ +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * A Doc Detective test. + */ +export type Test = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +export interface Report { + /** + * Unique identifier for the test specification. + */ + reportId?: string; + /** + * Test specifications that were performed. + * + * @minItems 1 + */ + specs: [Specification, ...Specification[]]; + [k: string]: unknown; +} +export interface Specification { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/spec_v3.schema.json"; + /** + * Unique identifier for the test specification. + */ + specId?: string; + /** + * Description of the test specification. + */ + description?: string; + /** + * Path to the test specification. + */ + specPath?: string; + /** + * Path to the content that the specification is associated with. + */ + contentPath?: string; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + /** + * [Tests](test) to perform. + * + * @minItems 1 + */ + tests: [Test, ...Test[]]; + [k: string]: unknown; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: ("chrome" | "firefox" | "safari" | "webkit") | Browser | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} +//# sourceMappingURL=report_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/report_v3.d.ts.map b/dist/types/generated/report_v3.d.ts.map new file mode 100644 index 00000000..c7df91c5 --- /dev/null +++ b/dist/types/generated/report_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"report_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/report_v3.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/types/generated/report_v3.js b/dist/types/generated/report_v3.js new file mode 100644 index 00000000..30fcf555 --- /dev/null +++ b/dist/types/generated/report_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from report_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=report_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/report_v3.js.map b/dist/types/generated/report_v3.js.map new file mode 100644 index 00000000..99f4de79 --- /dev/null +++ b/dist/types/generated/report_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"report_v3.js","sourceRoot":"","sources":["../../../src/types/generated/report_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/resolvedTests_v3.d.ts b/dist/types/generated/resolvedTests_v3.d.ts new file mode 100644 index 00000000..a22de7f6 --- /dev/null +++ b/dist/types/generated/resolvedTests_v3.d.ts @@ -0,0 +1,571 @@ +/** + * Auto-generated from resolvedTests_v3.schema.json + * Do not edit manually + */ +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables = string; +export type FileTypePredefined = "markdown" | "asciidoc" | "html" | "dita"; +export type FileTypeCustom = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Perform a native shell command. + */ +export type RunShell = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +}; +/** + * Configuration for Heretto CMS integrations. Each entry specifies a Heretto instance and a scenario to build and test. + */ +export type HerettoCMSIntegrations = HerettoCMSIntegration[]; +/** + * OpenAPI description and configuration. + */ +export type OpenApi1 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * A Doc Detective test. + */ +export type Test = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * A collection of resolved tests ready to be performed. + */ +export interface ResolvedTests { + /** + * Unique identifier for the resolved tests. + */ + resolvedTestsId?: string; + config?: Config; + /** + * Test specifications that were performed. + * + * @minItems 1 + */ + specs: [Specification, ...Specification[]]; + [k: string]: unknown; +} +/** + * Configuration options for Doc Detective operations. + */ +export interface Config { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/config_v3.schema.json"; + /** + * Identifier for the configuration. + */ + configId?: string; + /** + * Path to the configuration file. + */ + configPath?: string; + /** + * Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files. + */ + input?: string | [string, ...string[]]; + /** + * Path of the directory in which to store the output of Doc Detective commands. If a file path is specified, Doc Detective attempts to honor the file name specified, but file path behavior is controlled by the configured reporters. + */ + output?: string; + /** + * If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specifications and source files. + */ + recursive?: boolean; + /** + * Whether paths should be interpreted as relative to the current working directory (`cwd`) or to the file in which they're specified (`file`). + */ + relativePathBase?: "cwd" | "file"; + loadVariables?: LoadVariables; + /** + * Default protocol and domain to use for relative URLs. + */ + origin?: string; + /** + * Path(s) to test specifications to perform before those specified by `input`. Useful for setting up testing environments. + */ + beforeAny?: string | string[]; + /** + * Path(s) to test specifications to perform after those specified by `input`. Useful for cleaning up testing environments. + */ + afterAll?: string | string[]; + /** + * Whether or not to detect steps in input files based on defined markup. + */ + detectSteps?: boolean; + /** + * Whether or not to run potentially unsafe steps, such as those that might modify files or system state. + */ + allowUnsafeSteps?: boolean; + /** + * If `true`, crawls sitemap.xml files specified by URL to find additional files to test. + */ + crawl?: boolean; + /** + * If `true`, processes DITA maps and includes generated files as inputs. + */ + processDitaMaps?: boolean; + /** + * Amount of detail to output when performing an operation. + */ + logLevel?: "silent" | "error" | "warning" | "info" | "debug"; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + /** + * Configuration for file types and their markup detection. + */ + fileTypes?: [ + FileTypePredefined | FileTypeCustom | FileTypeExecutable, + ...(FileTypePredefined | FileTypeCustom | FileTypeExecutable)[] + ]; + integrations?: IntegrationsOptions; + telemetry?: TelemetryOptions; + /** + * Number of concurrent test runners. Set to true to use CPU core count (capped at 4). + */ + concurrentRunners?: number | boolean; + environment?: EnvironmentDetails; + /** + * Enable debugging mode. `true` allows pausing on breakpoints, waiting for user input before continuing. `stepThrough` pauses at every step, waiting for user input before continuing. `false` disables all debugging. + */ + debug?: boolean | "stepThrough"; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: ("chrome" | "firefox" | "safari" | "webkit") | Browser | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface FileTypeExecutable { + /** + * File extensions to use with type. + */ + extensions: string | [string, ...string[]]; + /** + * `runShell` step to perform for this file type. Use $1 as a placeholder for the file path. + */ + runShell?: RunShell; + [k: string]: unknown; +} +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +/** + * Options for connecting to external services. + */ +export interface IntegrationsOptions { + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + docDetectiveApi?: DocDetectiveOrchestrationAPI; + heretto?: HerettoCMSIntegrations; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} +/** + * Configuration for Doc Detective Orchestration API integration. + */ +export interface DocDetectiveOrchestrationAPI { + /** + * API key for authenticating with the Doc Detective Orchestration API. + */ + apiKey?: string; +} +export interface HerettoCMSIntegration { + /** + * Unique identifier for this Heretto integration. Used in logs and results. + */ + name: string; + /** + * The organization subdomain used to access Heretto CCMS (e.g., 'thunderbird' for thunderbird.heretto.com). + */ + organizationId: string; + /** + * Heretto CCMS username (email address) for API authentication. + */ + username: string; + /** + * API token generated in Heretto CCMS for authentication. See https://help.heretto.com/en/heretto-ccms/api/ccms-api-authentication/basic-authentication#ariaid-title3 + */ + apiToken: string; + /** + * Name of the scenario to build and test. + */ + scenarioName?: string; + /** + * Local path where Heretto content was downloaded. Set automatically during processing. + */ + outputPath?: string; + /** + * Mapping of local file paths to Heretto file metadata. Set automatically during content loading. + */ + fileMapping?: { + [k: string]: { + /** + * The UUID of the file in Heretto. + */ + fileId?: string; + /** + * The path of the file in Heretto. + */ + filePath?: string; + [k: string]: unknown; + }; + }; + /** + * If `true`, uploads changed screenshots and other media files back to Heretto CMS after test execution. + */ + uploadOnChange?: boolean; + /** + * Mapping of Heretto file paths to their UUIDs and metadata. Set automatically during content loading by fetching ditamap resource dependencies. + */ + resourceDependencies?: { + [k: string]: { + /** + * The UUID of the file in Heretto. + */ + uuid?: string; + /** + * The full xmldb path of the file in Heretto. + */ + fullPath?: string; + /** + * The file name. + */ + name?: string; + /** + * The UUID of the parent folder in Heretto. + */ + parentFolderId?: string; + [k: string]: unknown; + }; + }; +} +/** + * Options around sending telemetry for Doc Detective usage. + */ +export interface TelemetryOptions { + /** + * If `true`, sends Doc Detective telemetry. + */ + send: boolean; + /** + * Identifier for the organization, group, or individual running Doc Detective. + */ + userId?: string; +} +/** + * Environment information for the system running Doc Detective. + */ +export interface EnvironmentDetails { + /** + * The current working directory of the process running Doc Detective. + */ + workingDirectory?: string; + /** + * The operating system type running Doc Detective. + */ + platform: "linux" | "mac" | "windows"; + /** + * The processor architecture of the system running Doc Detective. + */ + arch?: "arm32" | "arm64" | "x32" | "x64"; +} +export interface Specification { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/spec_v3.schema.json"; + /** + * Unique identifier for the test specification. + */ + specId?: string; + /** + * Description of the test specification. + */ + description?: string; + /** + * Path to the test specification. + */ + specPath?: string; + /** + * Path to the content that the specification is associated with. + */ + contentPath?: string; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context1[]; + openApi?: (OpenApi1 & OpenAPIDescriptionTest1)[]; + /** + * [Tests](test) to perform. + * + * @minItems 1 + */ + tests: [Test, ...Test[]]; + [k: string]: unknown; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context1 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: ("chrome" | "firefox" | "safari" | "webkit") | Browser2 | (("chrome" | "firefox" | "safari" | "webkit") | Browser3)[]; +} +/** + * Browser configuration. + */ +export interface Browser2 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow2; + viewport?: BrowserViewport2; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow2 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport2 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser3 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow3; + viewport?: BrowserViewport3; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow3 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport3 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest1 { + [k: string]: unknown; +} +//# sourceMappingURL=resolvedTests_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/resolvedTests_v3.d.ts.map b/dist/types/generated/resolvedTests_v3.d.ts.map new file mode 100644 index 00000000..8e587642 --- /dev/null +++ b/dist/types/generated/resolvedTests_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"resolvedTests_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/resolvedTests_v3.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/types/generated/resolvedTests_v3.js b/dist/types/generated/resolvedTests_v3.js new file mode 100644 index 00000000..47ff3de0 --- /dev/null +++ b/dist/types/generated/resolvedTests_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from resolvedTests_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=resolvedTests_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/resolvedTests_v3.js.map b/dist/types/generated/resolvedTests_v3.js.map new file mode 100644 index 00000000..bc6670eb --- /dev/null +++ b/dist/types/generated/resolvedTests_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"resolvedTests_v3.js","sourceRoot":"","sources":["../../../src/types/generated/resolvedTests_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/runCode_v3.d.ts b/dist/types/generated/runCode_v3.d.ts new file mode 100644 index 00000000..f28ae44c --- /dev/null +++ b/dist/types/generated/runCode_v3.d.ts @@ -0,0 +1,57 @@ +/** + * Auto-generated from runCode_v3.schema.json + * Do not edit manually + */ +/** + * Assemble and run code. + */ +export type RunCode = RunCodeDetailed; +export interface RunCodeDetailed { + /** + * Language of the code to run. + */ + language: "python" | "bash" | "javascript"; + /** + * Code to run. + */ + code: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; + [k: string]: unknown; +} +//# sourceMappingURL=runCode_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/runCode_v3.d.ts.map b/dist/types/generated/runCode_v3.d.ts.map new file mode 100644 index 00000000..0bc2e3ef --- /dev/null +++ b/dist/types/generated/runCode_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"runCode_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/runCode_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,eAAe,CAAC;AAEtC,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,YAAY,CAAC;IAC3C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB"} \ No newline at end of file diff --git a/dist/types/generated/runCode_v3.js b/dist/types/generated/runCode_v3.js new file mode 100644 index 00000000..c86160c8 --- /dev/null +++ b/dist/types/generated/runCode_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from runCode_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=runCode_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/runCode_v3.js.map b/dist/types/generated/runCode_v3.js.map new file mode 100644 index 00000000..bdae44dd --- /dev/null +++ b/dist/types/generated/runCode_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"runCode_v3.js","sourceRoot":"","sources":["../../../src/types/generated/runCode_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/runShell_v3.d.ts b/dist/types/generated/runShell_v3.d.ts new file mode 100644 index 00000000..8a6bf1b0 --- /dev/null +++ b/dist/types/generated/runShell_v3.d.ts @@ -0,0 +1,56 @@ +/** + * Auto-generated from runShell_v3.schema.json + * Do not edit manually + */ +/** + * Perform a native shell command. + */ +export type RunShell = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +//# sourceMappingURL=runShell_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/runShell_v3.d.ts.map b/dist/types/generated/runShell_v3.d.ts.map new file mode 100644 index 00000000..fac795fd --- /dev/null +++ b/dist/types/generated/runShell_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"runShell_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/runShell_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,qBAAqB,GAAG,uBAAuB,CAAC;AACvE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE3C,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"} \ No newline at end of file diff --git a/dist/types/generated/runShell_v3.js b/dist/types/generated/runShell_v3.js new file mode 100644 index 00000000..0344000b --- /dev/null +++ b/dist/types/generated/runShell_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from runShell_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=runShell_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/runShell_v3.js.map b/dist/types/generated/runShell_v3.js.map new file mode 100644 index 00000000..4699103a --- /dev/null +++ b/dist/types/generated/runShell_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"runShell_v3.js","sourceRoot":"","sources":["../../../src/types/generated/runShell_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/saveCookie_v3.d.ts b/dist/types/generated/saveCookie_v3.d.ts new file mode 100644 index 00000000..3d527f9e --- /dev/null +++ b/dist/types/generated/saveCookie_v3.d.ts @@ -0,0 +1,16 @@ +/** + * Auto-generated from saveCookie_v3.schema.json + * Do not edit manually + */ +/** + * Save a specific browser cookie to a file or environment variable for later reuse. + */ +export type SaveCookie = CookieName | SaveCookieDetailed; +/** + * Name of the specific cookie to save. Will be saved to a default file path or environment variable. + */ +export type CookieName = string; +export type SaveCookieDetailed = { + [k: string]: unknown; +}; +//# sourceMappingURL=saveCookie_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/saveCookie_v3.d.ts.map b/dist/types/generated/saveCookie_v3.d.ts.map new file mode 100644 index 00000000..b64364ef --- /dev/null +++ b/dist/types/generated/saveCookie_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"saveCookie_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/saveCookie_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,kBAAkB,CAAC;AACzD;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAChC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC"} \ No newline at end of file diff --git a/dist/types/generated/saveCookie_v3.js b/dist/types/generated/saveCookie_v3.js new file mode 100644 index 00000000..3d20ebd9 --- /dev/null +++ b/dist/types/generated/saveCookie_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from saveCookie_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=saveCookie_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/saveCookie_v3.js.map b/dist/types/generated/saveCookie_v3.js.map new file mode 100644 index 00000000..2847053f --- /dev/null +++ b/dist/types/generated/saveCookie_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"saveCookie_v3.js","sourceRoot":"","sources":["../../../src/types/generated/saveCookie_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/screenshot_v3.d.ts b/dist/types/generated/screenshot_v3.d.ts new file mode 100644 index 00000000..4250f0ce --- /dev/null +++ b/dist/types/generated/screenshot_v3.d.ts @@ -0,0 +1,74 @@ +/** + * Auto-generated from screenshot_v3.schema.json + * Do not edit manually + */ +/** + * Takes a screenshot in PNG format. + */ +export type Screenshot = ScreenshotSimple | CaptureScreenshotDetailed | CaptureScreenshot; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple = string; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple1 = string; +/** + * Display text or selector of the element to screenshot. + */ +export type CropByElementSimple = string; +/** + * Crop the screenshot to a specific element. + */ +export type CropByElementDetailed = { + [k: string]: unknown; +}; +/** + * If `true`, captures a screenshot. If `false`, doesn't capture a screenshot. + */ +export type CaptureScreenshot = boolean; +export interface CaptureScreenshotDetailed { + path?: ScreenshotSimple1; + /** + * Directory of the PNG file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing screenshot at `path` if it exists. + * If `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + crop?: CropByElementSimple | CropByElementDetailed; + sourceIntegration?: SourceIntegration; +} +/** + * Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations. + */ +export interface SourceIntegration { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} +//# sourceMappingURL=screenshot_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/screenshot_v3.d.ts.map b/dist/types/generated/screenshot_v3.d.ts.map new file mode 100644 index 00000000..059e0c33 --- /dev/null +++ b/dist/types/generated/screenshot_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"screenshot_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/screenshot_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,gBAAgB,GAAG,yBAAyB,GAAG,iBAAiB,CAAC;AAC1F;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACtC;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AACzC;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAExC,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD,IAAI,CAAC,EAAE,mBAAmB,GAAG,qBAAqB,CAAC;IACnD,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC;AACD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC;IAChB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"} \ No newline at end of file diff --git a/dist/types/generated/screenshot_v3.js b/dist/types/generated/screenshot_v3.js new file mode 100644 index 00000000..55a24991 --- /dev/null +++ b/dist/types/generated/screenshot_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from screenshot_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=screenshot_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/screenshot_v3.js.map b/dist/types/generated/screenshot_v3.js.map new file mode 100644 index 00000000..dc948dfa --- /dev/null +++ b/dist/types/generated/screenshot_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"screenshot_v3.js","sourceRoot":"","sources":["../../../src/types/generated/screenshot_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/sourceIntegration_v3.d.ts b/dist/types/generated/sourceIntegration_v3.d.ts new file mode 100644 index 00000000..1379f244 --- /dev/null +++ b/dist/types/generated/sourceIntegration_v3.d.ts @@ -0,0 +1,30 @@ +/** + * Auto-generated from sourceIntegration_v3.schema.json + * Do not edit manually + */ +/** + * Information about the source integration for a file, enabling upload of changed files back to the source CMS. + */ +export interface SourceIntegration { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} +//# sourceMappingURL=sourceIntegration_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/sourceIntegration_v3.d.ts.map b/dist/types/generated/sourceIntegration_v3.d.ts.map new file mode 100644 index 00000000..d995ccc8 --- /dev/null +++ b/dist/types/generated/sourceIntegration_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"sourceIntegration_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/sourceIntegration_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC;IAChB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"} \ No newline at end of file diff --git a/dist/types/generated/sourceIntegration_v3.js b/dist/types/generated/sourceIntegration_v3.js new file mode 100644 index 00000000..3948c292 --- /dev/null +++ b/dist/types/generated/sourceIntegration_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from sourceIntegration_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=sourceIntegration_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/sourceIntegration_v3.js.map b/dist/types/generated/sourceIntegration_v3.js.map new file mode 100644 index 00000000..05caba88 --- /dev/null +++ b/dist/types/generated/sourceIntegration_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sourceIntegration_v3.js","sourceRoot":"","sources":["../../../src/types/generated/sourceIntegration_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/spec_v3.d.ts b/dist/types/generated/spec_v3.d.ts new file mode 100644 index 00000000..c5725df4 --- /dev/null +++ b/dist/types/generated/spec_v3.d.ts @@ -0,0 +1,159 @@ +/** + * Auto-generated from spec_v3.schema.json + * Do not edit manually + */ +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +}; +/** + * A Doc Detective test. + */ +export type Test = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +export interface Specification { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/spec_v3.schema.json"; + /** + * Unique identifier for the test specification. + */ + specId?: string; + /** + * Description of the test specification. + */ + description?: string; + /** + * Path to the test specification. + */ + specPath?: string; + /** + * Path to the content that the specification is associated with. + */ + contentPath?: string; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + /** + * [Tests](test) to perform. + * + * @minItems 1 + */ + tests: [Test, ...Test[]]; + [k: string]: unknown; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: ("chrome" | "firefox" | "safari" | "webkit") | Browser | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} +//# sourceMappingURL=spec_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/spec_v3.d.ts.map b/dist/types/generated/spec_v3.d.ts.map new file mode 100644 index 00000000..d0b095bb --- /dev/null +++ b/dist/types/generated/spec_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"spec_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/spec_v3.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/types/generated/spec_v3.js b/dist/types/generated/spec_v3.js new file mode 100644 index 00000000..768b6153 --- /dev/null +++ b/dist/types/generated/spec_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from spec_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=spec_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/spec_v3.js.map b/dist/types/generated/spec_v3.js.map new file mode 100644 index 00000000..f67faf5d --- /dev/null +++ b/dist/types/generated/spec_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"spec_v3.js","sourceRoot":"","sources":["../../../src/types/generated/spec_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/step_v3.d.ts b/dist/types/generated/step_v3.d.ts new file mode 100644 index 00000000..6b4e1a9b --- /dev/null +++ b/dist/types/generated/step_v3.d.ts @@ -0,0 +1,1270 @@ +/** + * Auto-generated from step_v3.schema.json + * Do not edit manually + */ +/** + * A step in a test. + */ +export type Step = (Common & CheckLink) | (Common1 & Click) | (Common2 & Find) | (Common3 & GoTo) | (Common4 & HttpRequest) | (Common5 & RunShell) | (Common6 & RunCode) | (Common7 & Type) | (Common8 & Screenshot) | (Common9 & SaveCookie) | (Common10 & Record) | (Common11 & StopRecord) | (Common12 & LoadVariables) | (Common13 & DragAndDrop) | (Common14 & LoadCookie) | (Common15 & Wait); +export type CheckLink1 = CheckLinkDetailed | CheckLinkDetailed1; +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export type CheckLinkDetailed = string; +/** + * Click or tap an element. + */ +export type Click1 = ClickElementSimple | ClickElementDetailed | boolean; +/** + * Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type ClickElementSimple = string; +export type ClickElementDetailed = { + [k: string]: unknown; +}; +/** + * Find an element based on display text or a selector, then optionally interact with it. + */ +export type Find1 = FindElementSimple | FindElementDetailed; +/** + * Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type FindElementSimple = string; +export type FindElementDetailed = { + [k: string]: unknown; +}; +export type GoTo1 = GoToURLSimple | GoToURLDetailed; +/** + * Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any. + */ +export type GoToURLSimple = string; +/** + * Perform a generic HTTP request, for example to an API. + */ +export type HttpRequest1 = HTTPRequestSimple | HTTPRequestDetailed; +/** + * URL for the HTTP request. + */ +export type HTTPRequestSimple = string; +export type HTTPRequestDetailed = { + [k: string]: unknown; +}; +/** + * Perform a native shell command. + */ +export type RunShell1 = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; +/** + * Assemble and run code. + */ +export type RunCode1 = RunCodeDetailed; +/** + * Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`. + */ +export type TypeKeys = TypeKeysSimple | TypeKeysDetailed; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple = string | string[]; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple1 = string | string[]; +/** + * Takes a screenshot in PNG format. + */ +export type Screenshot1 = ScreenshotSimple | CaptureScreenshotDetailed | CaptureScreenshot; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple = string; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple1 = string; +/** + * Display text or selector of the element to screenshot. + */ +export type CropByElementSimple = string; +/** + * Crop the screenshot to a specific element. + */ +export type CropByElementDetailed = { + [k: string]: unknown; +}; +/** + * If `true`, captures a screenshot. If `false`, doesn't capture a screenshot. + */ +export type CaptureScreenshot = boolean; +/** + * Save a specific browser cookie to a file or environment variable for later reuse. + */ +export type SaveCookie1 = CookieName | SaveCookieDetailed; +/** + * Name of the specific cookie to save. Will be saved to a default file path or environment variable. + */ +export type CookieName = string; +export type SaveCookieDetailed = { + [k: string]: unknown; +}; +/** + * Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ] + */ +export type Record1 = RecordSimple | RecordDetailed | RecordBoolean; +/** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ +export type RecordSimple = string; +/** + * If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport. + */ +export type RecordBoolean = boolean; +/** + * Stop the current recording. + */ +export type StopRecord1 = boolean; +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables1 = string; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple = string; +export type ElementDetailed = { + [k: string]: unknown; +}; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple1 = string; +export type ElementDetailed1 = { + [k: string]: unknown; +}; +/** + * Load a specific cookie from a file or environment variable into the browser. + */ +export type LoadCookie1 = CookieNameOrFilePath | LoadCookieDetailed; +/** + * Name of the specific cookie to load from default location, or file path to cookie file. + */ +export type CookieNameOrFilePath = string; +export type LoadCookieDetailed = { + [k: string]: unknown; +}; +/** + * Pause (in milliseconds) before performing the next action. + */ +export type Wait1 = WaitSimple | WaitEnvironmentVariable | WaitBoolean; +export type WaitSimple = number; +export type WaitEnvironmentVariable = string; +export type WaitBoolean = boolean; +export interface Common { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep; + variables?: VariablesStep; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface CheckLink { + checkLink: CheckLink1; + [k: string]: unknown; +} +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export interface CheckLinkDetailed1 { + /** + * URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. + */ + statusCodes?: number | number[]; +} +export interface Common1 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep1; + variables?: VariablesStep1; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep1 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep1`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep1 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep1`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Click { + click: Click1; + [k: string]: unknown; +} +export interface Common2 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep2; + variables?: VariablesStep2; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep2 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep2`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep2 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep2`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Find { + find: Find1; + [k: string]: unknown; +} +export interface Common3 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep3; + variables?: VariablesStep3; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep3 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep3`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep3 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep3`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface GoTo { + goTo: GoTo1; + [k: string]: unknown; +} +/** + * Navigate to an HTTP or HTTPS URL. + */ +export interface GoToURLDetailed { + /** + * URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails. + */ + timeout?: number; + /** + * Configuration for waiting conditions after navigation. + */ + waitUntil?: { + /** + * Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check. + */ + networkIdleTime?: number | null; + /** + * Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check. + */ + domIdleTime?: number | null; + /** + * Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified. + */ + find?: { + [k: string]: unknown; + }; + }; +} +export interface Common4 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep4; + variables?: VariablesStep4; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep4 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep4`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep4 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep4`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface HttpRequest { + httpRequest: HttpRequest1; + [k: string]: unknown; +} +export interface Common5 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep5; + variables?: VariablesStep5; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep5 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep5`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep5 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep5`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunShell { + runShell: RunShell1; + [k: string]: unknown; +} +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +export interface Common6 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep6; + variables?: VariablesStep6; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep6 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep6`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep6 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep6`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunCode { + runCode: RunCode1; + [k: string]: unknown; +} +export interface RunCodeDetailed { + /** + * Language of the code to run. + */ + language: "python" | "bash" | "javascript"; + /** + * Code to run. + */ + code: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; + [k: string]: unknown; +} +export interface Common7 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep7; + variables?: VariablesStep7; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep7 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep7`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep7 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep7`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Type { + type: TypeKeys; + [k: string]: unknown; +} +export interface TypeKeysDetailed { + keys: TypeKeysSimple1; + /** + * Delay in milliseconds between each key press during a recording + */ + inputDelay?: number; + /** + * Selector for the element to type into. If not specified, the typing occurs in the active element. + */ + selector?: string; + /** + * Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria. + */ + elementText?: string; + /** + * ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementId?: string; + /** + * data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementTestId?: string; + /** + * Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes. + */ + elementClass?: string | string[]; + /** + * Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence. + */ + elementAttribute?: { + [k: string]: string | number | boolean; + }; + /** + * Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementAria?: string; +} +export interface Common8 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep8; + variables?: VariablesStep8; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep8 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep8`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep8 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep8`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Screenshot { + screenshot: Screenshot1; + [k: string]: unknown; +} +export interface CaptureScreenshotDetailed { + path?: ScreenshotSimple1; + /** + * Directory of the PNG file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing screenshot at `path` if it exists. + * If `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + crop?: CropByElementSimple | CropByElementDetailed; + sourceIntegration?: SourceIntegration; +} +/** + * Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations. + */ +export interface SourceIntegration { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} +export interface Common9 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep9; + variables?: VariablesStep9; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep9 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep9`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep9 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep9`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface SaveCookie { + saveCookie: SaveCookie1; + [k: string]: unknown; +} +export interface Common10 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep10; + variables?: VariablesStep10; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep10 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep10`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep10 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep10`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Record { + record: Record1; + [k: string]: unknown; +} +export interface RecordDetailed { + /** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ + path?: string; + /** + * Directory of the file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * If `true`, overwrites the existing recording at `path` if it exists. + */ + overwrite?: "true" | "false"; + [k: string]: unknown; +} +export interface Common11 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep11; + variables?: VariablesStep11; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep11 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep11`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep11 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep11`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface StopRecord { + stopRecord: StopRecord1; + [k: string]: unknown; +} +export interface Common12 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep12; + variables?: VariablesStep12; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep12 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep12`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep12 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep12`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadVariables { + loadVariables: LoadVariables1; + [k: string]: unknown; +} +export interface Common13 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep13; + variables?: VariablesStep13; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep13 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep13`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep13 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep13`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface DragAndDrop { + dragAndDrop: DragAndDrop1; + [k: string]: unknown; +} +/** + * Drag and drop an element from source to target. + */ +export interface DragAndDrop1 { + /** + * The element to drag. + */ + source: ElementSimple | ElementDetailed; + /** + * The target location to drop the element. + */ + target: ElementSimple1 | ElementDetailed1; + /** + * Duration of the drag operation in milliseconds. + */ + duration?: number; + [k: string]: unknown; +} +export interface Common14 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep14; + variables?: VariablesStep14; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep14 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep14`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep14 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep14`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadCookie { + loadCookie: LoadCookie1; + [k: string]: unknown; +} +export interface Common15 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep15; + variables?: VariablesStep15; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep15 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep15`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep15 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep15`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Wait { + wait: Wait1; + [k: string]: unknown; +} +//# sourceMappingURL=step_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/step_v3.d.ts.map b/dist/types/generated/step_v3.d.ts.map new file mode 100644 index 00000000..9d81de0e --- /dev/null +++ b/dist/types/generated/step_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"step_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/step_v3.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/types/generated/step_v3.js b/dist/types/generated/step_v3.js new file mode 100644 index 00000000..5c252f76 --- /dev/null +++ b/dist/types/generated/step_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from step_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=step_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/step_v3.js.map b/dist/types/generated/step_v3.js.map new file mode 100644 index 00000000..2218dcfa --- /dev/null +++ b/dist/types/generated/step_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"step_v3.js","sourceRoot":"","sources":["../../../src/types/generated/step_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/stopRecord_v3.d.ts b/dist/types/generated/stopRecord_v3.d.ts new file mode 100644 index 00000000..24a65f43 --- /dev/null +++ b/dist/types/generated/stopRecord_v3.d.ts @@ -0,0 +1,9 @@ +/** + * Auto-generated from stopRecord_v3.schema.json + * Do not edit manually + */ +/** + * Stop the current recording. + */ +export type StopRecord = boolean; +//# sourceMappingURL=stopRecord_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/stopRecord_v3.d.ts.map b/dist/types/generated/stopRecord_v3.d.ts.map new file mode 100644 index 00000000..3f3ef193 --- /dev/null +++ b/dist/types/generated/stopRecord_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"stopRecord_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/stopRecord_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC"} \ No newline at end of file diff --git a/dist/types/generated/stopRecord_v3.js b/dist/types/generated/stopRecord_v3.js new file mode 100644 index 00000000..a92b8eb3 --- /dev/null +++ b/dist/types/generated/stopRecord_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from stopRecord_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=stopRecord_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/stopRecord_v3.js.map b/dist/types/generated/stopRecord_v3.js.map new file mode 100644 index 00000000..8ded45b9 --- /dev/null +++ b/dist/types/generated/stopRecord_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"stopRecord_v3.js","sourceRoot":"","sources":["../../../src/types/generated/stopRecord_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/test_v3.d.ts b/dist/types/generated/test_v3.d.ts new file mode 100644 index 00000000..baede53f --- /dev/null +++ b/dist/types/generated/test_v3.d.ts @@ -0,0 +1,2915 @@ +/** + * Auto-generated from test_v3.schema.json + * Do not edit manually + */ +/** + * A Doc Detective test. + */ +export type Test = { + [k: string]: unknown; +} & { + /** + * Unique identifier for the test. + */ + testId?: string; + /** + * Description of the test. + */ + description?: string; + /** + * Path to the content that the test is associated with. + */ + contentPath?: string; + /** + * Whether or not to detect steps in input files based on markup regex. + */ + detectSteps?: boolean; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + /** + * Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec. + */ + before?: string; + /** + * Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec. + */ + after?: string; + /** + * Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed. + * + * @minItems 1 + */ + steps?: [Step, ...Step[]]; + contexts?: ResolvedContexts; +}; +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +}; +/** + * A step in a test. + */ +export type Step = (Common & CheckLink) | (Common1 & Click) | (Common2 & Find) | (Common3 & GoTo) | (Common4 & HttpRequest) | (Common5 & RunShell) | (Common6 & RunCode) | (Common7 & Type) | (Common8 & Screenshot) | (Common9 & SaveCookie) | (Common10 & Record) | (Common11 & StopRecord) | (Common12 & LoadVariables) | (Common13 & DragAndDrop) | (Common14 & LoadCookie) | (Common15 & Wait); +export type CheckLink1 = CheckLinkDetailed | CheckLinkDetailed1; +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export type CheckLinkDetailed = string; +/** + * Click or tap an element. + */ +export type Click1 = ClickElementSimple | ClickElementDetailed | boolean; +/** + * Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type ClickElementSimple = string; +export type ClickElementDetailed = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Find an element based on display text or a selector, then optionally interact with it. + */ +export type Find1 = FindElementSimple | FindElementDetailed; +/** + * Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type FindElementSimple = string; +export type FindElementDetailed = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +export type GoTo1 = GoToURLSimple | GoToURLDetailed; +/** + * Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any. + */ +export type GoToURLSimple = string; +/** + * Perform a generic HTTP request, for example to an API. + */ +export type HttpRequest1 = HTTPRequestSimple | HTTPRequestDetailed; +/** + * URL for the HTTP request. + */ +export type HTTPRequestSimple = string; +export type HTTPRequestDetailed = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Perform a native shell command. + */ +export type RunShell1 = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; +/** + * Assemble and run code. + */ +export type RunCode1 = RunCodeDetailed; +/** + * Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`. + */ +export type TypeKeys = TypeKeysSimple | TypeKeysDetailed; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple = string | string[]; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple1 = string | string[]; +/** + * Takes a screenshot in PNG format. + */ +export type Screenshot1 = ScreenshotSimple | CaptureScreenshotDetailed | CaptureScreenshot; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple = string; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple1 = string; +/** + * Display text or selector of the element to screenshot. + */ +export type CropByElementSimple = string; +/** + * Crop the screenshot to a specific element. + */ +export type CropByElementDetailed = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * If `true`, captures a screenshot. If `false`, doesn't capture a screenshot. + */ +export type CaptureScreenshot = boolean; +/** + * Save a specific browser cookie to a file or environment variable for later reuse. + */ +export type SaveCookie1 = CookieName | SaveCookieDetailed; +/** + * Name of the specific cookie to save. Will be saved to a default file path or environment variable. + */ +export type CookieName = string; +export type SaveCookieDetailed = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ] + */ +export type Record1 = RecordSimple | RecordDetailed | RecordBoolean; +/** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ +export type RecordSimple = string; +/** + * If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport. + */ +export type RecordBoolean = boolean; +/** + * Stop the current recording. + */ +export type StopRecord1 = boolean; +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables1 = string; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple = string; +export type ElementDetailed = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple1 = string; +export type ElementDetailed1 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Load a specific cookie from a file or environment variable into the browser. + */ +export type LoadCookie1 = CookieNameOrFilePath | LoadCookieDetailed; +/** + * Name of the specific cookie to load from default location, or file path to cookie file. + */ +export type CookieNameOrFilePath = string; +export type LoadCookieDetailed = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Pause (in milliseconds) before performing the next action. + */ +export type Wait1 = WaitSimple | WaitEnvironmentVariable | WaitBoolean; +export type WaitSimple = number; +export type WaitEnvironmentVariable = string; +export type WaitBoolean = boolean; +/** + * OpenAPI description and configuration. + */ +export type OpenApi1 = { + [k: string]: unknown; +}; +/** + * A step in a test. + */ +export type Step1 = (Common16 & CheckLink2) | (Common17 & Click2) | (Common18 & Find2) | (Common19 & GoTo2) | (Common20 & HttpRequest2) | (Common21 & RunShell2) | (Common22 & RunCode2) | (Common23 & Type1) | (Common24 & Screenshot2) | (Common25 & SaveCookie2) | (Common26 & Record2) | (Common27 & StopRecord2) | (Common28 & LoadVariables2) | (Common29 & DragAndDrop2) | (Common30 & LoadCookie2) | (Common31 & Wait2); +export type CheckLink3 = CheckLinkDetailed2 | CheckLinkDetailed3; +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export type CheckLinkDetailed2 = string; +/** + * Click or tap an element. + */ +export type Click3 = ClickElementSimple1 | ClickElementDetailed1 | boolean; +/** + * Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type ClickElementSimple1 = string; +export type ClickElementDetailed1 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Find an element based on display text or a selector, then optionally interact with it. + */ +export type Find3 = FindElementSimple1 | FindElementDetailed1; +/** + * Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type FindElementSimple1 = string; +export type FindElementDetailed1 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +export type GoTo3 = GoToURLSimple1 | GoToURLDetailed1; +/** + * Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any. + */ +export type GoToURLSimple1 = string; +/** + * Perform a generic HTTP request, for example to an API. + */ +export type HttpRequest3 = HTTPRequestSimple1 | HTTPRequestDetailed1; +/** + * URL for the HTTP request. + */ +export type HTTPRequestSimple1 = string; +export type HTTPRequestDetailed1 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Perform a native shell command. + */ +export type RunShell3 = RunShellCommandSimple1 | RunShellCommandDetailed1; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple1 = string; +/** + * Assemble and run code. + */ +export type RunCode3 = RunCodeDetailed1; +/** + * Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`. + */ +export type TypeKeys1 = TypeKeysSimple2 | TypeKeysDetailed1; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple2 = string | string[]; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple3 = string | string[]; +/** + * Takes a screenshot in PNG format. + */ +export type Screenshot3 = ScreenshotSimple2 | CaptureScreenshotDetailed1 | CaptureScreenshot1; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple2 = string; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple3 = string; +/** + * Display text or selector of the element to screenshot. + */ +export type CropByElementSimple1 = string; +/** + * Crop the screenshot to a specific element. + */ +export type CropByElementDetailed1 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * If `true`, captures a screenshot. If `false`, doesn't capture a screenshot. + */ +export type CaptureScreenshot1 = boolean; +/** + * Save a specific browser cookie to a file or environment variable for later reuse. + */ +export type SaveCookie3 = CookieName1 | SaveCookieDetailed1; +/** + * Name of the specific cookie to save. Will be saved to a default file path or environment variable. + */ +export type CookieName1 = string; +export type SaveCookieDetailed1 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ] + */ +export type Record3 = RecordSimple1 | RecordDetailed1 | RecordBoolean1; +/** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ +export type RecordSimple1 = string; +/** + * If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport. + */ +export type RecordBoolean1 = boolean; +/** + * Stop the current recording. + */ +export type StopRecord3 = boolean; +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables3 = string; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple2 = string; +export type ElementDetailed2 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple3 = string; +export type ElementDetailed3 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Load a specific cookie from a file or environment variable into the browser. + */ +export type LoadCookie3 = CookieNameOrFilePath1 | LoadCookieDetailed1; +/** + * Name of the specific cookie to load from default location, or file path to cookie file. + */ +export type CookieNameOrFilePath1 = string; +export type LoadCookieDetailed1 = { + [k: string]: unknown; +} | { + [k: string]: unknown; +}; +/** + * Pause (in milliseconds) before performing the next action. + */ +export type Wait3 = WaitSimple1 | WaitEnvironmentVariable1 | WaitBoolean1; +export type WaitSimple1 = number; +export type WaitEnvironmentVariable1 = string; +export type WaitBoolean1 = boolean; +/** + * Resolved contexts to run the test in. This is a resolved version of the `runOn` property. It is not user-defined and should not be used in test specifications. + */ +export type ResolvedContexts = ResolvedContext[]; +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: ("chrome" | "firefox" | "safari" | "webkit") | Browser | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} +export interface Common { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep; + variables?: VariablesStep; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface CheckLink { + checkLink: CheckLink1; + [k: string]: unknown; +} +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export interface CheckLinkDetailed1 { + /** + * URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. + */ + statusCodes?: number | number[]; +} +export interface Common1 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep1; + variables?: VariablesStep1; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep1 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep1`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep1 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep1`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Click { + click: Click1; + [k: string]: unknown; +} +export interface Common2 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep2; + variables?: VariablesStep2; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep2 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep2`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep2 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep2`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Find { + find: Find1; + [k: string]: unknown; +} +export interface Common3 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep3; + variables?: VariablesStep3; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep3 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep3`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep3 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep3`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface GoTo { + goTo: GoTo1; + [k: string]: unknown; +} +/** + * Navigate to an HTTP or HTTPS URL. + */ +export interface GoToURLDetailed { + /** + * URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails. + */ + timeout?: number; + /** + * Configuration for waiting conditions after navigation. + */ + waitUntil?: { + /** + * Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check. + */ + networkIdleTime?: number | null; + /** + * Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check. + */ + domIdleTime?: number | null; + /** + * Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified. + */ + find?: { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + }; + }; +} +export interface Common4 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep4; + variables?: VariablesStep4; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep4 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep4`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep4 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep4`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface HttpRequest { + httpRequest: HttpRequest1; + [k: string]: unknown; +} +export interface Common5 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep5; + variables?: VariablesStep5; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep5 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep5`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep5 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep5`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunShell { + runShell: RunShell1; + [k: string]: unknown; +} +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +export interface Common6 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep6; + variables?: VariablesStep6; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep6 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep6`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep6 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep6`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunCode { + runCode: RunCode1; + [k: string]: unknown; +} +export interface RunCodeDetailed { + /** + * Language of the code to run. + */ + language: "python" | "bash" | "javascript"; + /** + * Code to run. + */ + code: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; + [k: string]: unknown; +} +export interface Common7 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep7; + variables?: VariablesStep7; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep7 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep7`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep7 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep7`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Type { + type: TypeKeys; + [k: string]: unknown; +} +export interface TypeKeysDetailed { + keys: TypeKeysSimple1; + /** + * Delay in milliseconds between each key press during a recording + */ + inputDelay?: number; + /** + * Selector for the element to type into. If not specified, the typing occurs in the active element. + */ + selector?: string; + /** + * Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria. + */ + elementText?: string; + /** + * ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementId?: string; + /** + * data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementTestId?: string; + /** + * Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes. + */ + elementClass?: string | string[]; + /** + * Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence. + */ + elementAttribute?: { + [k: string]: string | number | boolean; + }; + /** + * Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementAria?: string; +} +export interface Common8 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep8; + variables?: VariablesStep8; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep8 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep8`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep8 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep8`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Screenshot { + screenshot: Screenshot1; + [k: string]: unknown; +} +export interface CaptureScreenshotDetailed { + path?: ScreenshotSimple1; + /** + * Directory of the PNG file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing screenshot at `path` if it exists. + * If `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + crop?: CropByElementSimple | CropByElementDetailed; + sourceIntegration?: SourceIntegration; +} +/** + * Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations. + */ +export interface SourceIntegration { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} +export interface Common9 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep9; + variables?: VariablesStep9; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep9 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep9`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep9 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep9`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface SaveCookie { + saveCookie: SaveCookie1; + [k: string]: unknown; +} +export interface Common10 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep10; + variables?: VariablesStep10; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep10 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep10`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep10 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep10`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Record { + record: Record1; + [k: string]: unknown; +} +export interface RecordDetailed { + /** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ + path?: string; + /** + * Directory of the file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * If `true`, overwrites the existing recording at `path` if it exists. + */ + overwrite?: "true" | "false"; + [k: string]: unknown; +} +export interface Common11 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep11; + variables?: VariablesStep11; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep11 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep11`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep11 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep11`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface StopRecord { + stopRecord: StopRecord1; + [k: string]: unknown; +} +export interface Common12 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep12; + variables?: VariablesStep12; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep12 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep12`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep12 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep12`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadVariables { + loadVariables: LoadVariables1; + [k: string]: unknown; +} +export interface Common13 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep13; + variables?: VariablesStep13; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep13 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep13`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep13 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep13`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface DragAndDrop { + dragAndDrop: DragAndDrop1; + [k: string]: unknown; +} +/** + * Drag and drop an element from source to target. + */ +export interface DragAndDrop1 { + /** + * The element to drag. + */ + source: ElementSimple | ElementDetailed; + /** + * The target location to drop the element. + */ + target: ElementSimple1 | ElementDetailed1; + /** + * Duration of the drag operation in milliseconds. + */ + duration?: number; + [k: string]: unknown; +} +export interface Common14 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep14; + variables?: VariablesStep14; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep14 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep14`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep14 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep14`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadCookie { + loadCookie: LoadCookie1; + [k: string]: unknown; +} +export interface Common15 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep15; + variables?: VariablesStep15; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep15 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep15`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep15 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep15`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Wait { + wait: Wait1; + [k: string]: unknown; +} +export interface ResolvedContext { + /** + * Platform to run the test on. This is a resolved version of the `platforms` property. + */ + platform?: string; + browser?: Browser2; + openApi?: (OpenApi1 & OpenAPIDescriptionTest1)[]; + /** + * Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed. + * + * @minItems 1 + */ + steps?: [Step1, ...Step1[]]; + [k: string]: unknown; +} +/** + * Browser configuration. + */ +export interface Browser2 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow2; + viewport?: BrowserViewport2; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow2 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport2 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest1 { + [k: string]: unknown; +} +export interface Common16 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep16; + variables?: VariablesStep16; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep16 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep16`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep16 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep16`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface CheckLink2 { + checkLink: CheckLink3; + [k: string]: unknown; +} +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export interface CheckLinkDetailed3 { + /** + * URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. + */ + statusCodes?: number | number[]; +} +export interface Common17 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep17; + variables?: VariablesStep17; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep17 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep17`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep17 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep17`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Click2 { + click: Click3; + [k: string]: unknown; +} +export interface Common18 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep18; + variables?: VariablesStep18; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep18 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep18`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep18 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep18`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Find2 { + find: Find3; + [k: string]: unknown; +} +export interface Common19 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep19; + variables?: VariablesStep19; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep19 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep19`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep19 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep19`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface GoTo2 { + goTo: GoTo3; + [k: string]: unknown; +} +/** + * Navigate to an HTTP or HTTPS URL. + */ +export interface GoToURLDetailed1 { + /** + * URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails. + */ + timeout?: number; + /** + * Configuration for waiting conditions after navigation. + */ + waitUntil?: { + /** + * Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check. + */ + networkIdleTime?: number | null; + /** + * Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check. + */ + domIdleTime?: number | null; + /** + * Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified. + */ + find?: { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + } | { + [k: string]: unknown; + }; + }; +} +export interface Common20 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep20; + variables?: VariablesStep20; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep20 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep20`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep20 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep20`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface HttpRequest2 { + httpRequest: HttpRequest3; + [k: string]: unknown; +} +export interface Common21 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep21; + variables?: VariablesStep21; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep21 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep21`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep21 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep21`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunShell2 { + runShell: RunShell3; + [k: string]: unknown; +} +export interface RunShellCommandDetailed1 { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +export interface Common22 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep22; + variables?: VariablesStep22; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep22 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep22`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep22 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep22`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunCode2 { + runCode: RunCode3; + [k: string]: unknown; +} +export interface RunCodeDetailed1 { + /** + * Language of the code to run. + */ + language: "python" | "bash" | "javascript"; + /** + * Code to run. + */ + code: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; + [k: string]: unknown; +} +export interface Common23 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep23; + variables?: VariablesStep23; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep23 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep23`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep23 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep23`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Type1 { + type: TypeKeys1; + [k: string]: unknown; +} +export interface TypeKeysDetailed1 { + keys: TypeKeysSimple3; + /** + * Delay in milliseconds between each key press during a recording + */ + inputDelay?: number; + /** + * Selector for the element to type into. If not specified, the typing occurs in the active element. + */ + selector?: string; + /** + * Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria. + */ + elementText?: string; + /** + * ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementId?: string; + /** + * data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementTestId?: string; + /** + * Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes. + */ + elementClass?: string | string[]; + /** + * Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence. + */ + elementAttribute?: { + [k: string]: string | number | boolean; + }; + /** + * Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementAria?: string; +} +export interface Common24 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep24; + variables?: VariablesStep24; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep24 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep24`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep24 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep24`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Screenshot2 { + screenshot: Screenshot3; + [k: string]: unknown; +} +export interface CaptureScreenshotDetailed1 { + path?: ScreenshotSimple3; + /** + * Directory of the PNG file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing screenshot at `path` if it exists. + * If `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + crop?: CropByElementSimple1 | CropByElementDetailed1; + sourceIntegration?: SourceIntegration1; +} +/** + * Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations. + */ +export interface SourceIntegration1 { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} +export interface Common25 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep25; + variables?: VariablesStep25; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep25 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep25`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep25 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep25`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface SaveCookie2 { + saveCookie: SaveCookie3; + [k: string]: unknown; +} +export interface Common26 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep26; + variables?: VariablesStep26; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep26 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep26`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep26 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep26`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Record2 { + record: Record3; + [k: string]: unknown; +} +export interface RecordDetailed1 { + /** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ + path?: string; + /** + * Directory of the file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * If `true`, overwrites the existing recording at `path` if it exists. + */ + overwrite?: "true" | "false"; + [k: string]: unknown; +} +export interface Common27 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep27; + variables?: VariablesStep27; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep27 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep27`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep27 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep27`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface StopRecord2 { + stopRecord: StopRecord3; + [k: string]: unknown; +} +export interface Common28 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep28; + variables?: VariablesStep28; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep28 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep28`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep28 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep28`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadVariables2 { + loadVariables: LoadVariables3; + [k: string]: unknown; +} +export interface Common29 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep29; + variables?: VariablesStep29; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep29 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep29`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep29 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep29`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface DragAndDrop2 { + dragAndDrop: DragAndDrop3; + [k: string]: unknown; +} +/** + * Drag and drop an element from source to target. + */ +export interface DragAndDrop3 { + /** + * The element to drag. + */ + source: ElementSimple2 | ElementDetailed2; + /** + * The target location to drop the element. + */ + target: ElementSimple3 | ElementDetailed3; + /** + * Duration of the drag operation in milliseconds. + */ + duration?: number; + [k: string]: unknown; +} +export interface Common30 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep30; + variables?: VariablesStep30; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep30 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep30`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep30 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep30`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadCookie2 { + loadCookie: LoadCookie3; + [k: string]: unknown; +} +export interface Common31 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep31; + variables?: VariablesStep31; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep31 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep31`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep31 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep31`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Wait2 { + wait: Wait3; + [k: string]: unknown; +} +//# sourceMappingURL=test_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/test_v3.d.ts.map b/dist/types/generated/test_v3.d.ts.map new file mode 100644 index 00000000..8868ef54 --- /dev/null +++ b/dist/types/generated/test_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"test_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/test_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG;IACjB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GAAG;IACF;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,OAAO,GAAG,sBAAsB,CAAC,EAAE,CAAC;IAC/C;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B,CAAC;AACF;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACF;;GAEG;AACH,MAAM,MAAM,IAAI,GACZ,CAAC,MAAM,GAAG,SAAS,CAAC,GACpB,CAAC,OAAO,GAAG,KAAK,CAAC,GACjB,CAAC,OAAO,GAAG,IAAI,CAAC,GAChB,CAAC,OAAO,GAAG,IAAI,CAAC,GAChB,CAAC,OAAO,GAAG,WAAW,CAAC,GACvB,CAAC,OAAO,GAAG,QAAQ,CAAC,GACpB,CAAC,OAAO,GAAG,OAAO,CAAC,GACnB,CAAC,OAAO,GAAG,IAAI,CAAC,GAChB,CAAC,OAAO,GAAG,UAAU,CAAC,GACtB,CAAC,OAAO,GAAG,UAAU,CAAC,GACtB,CAAC,QAAQ,GAAG,MAAM,CAAC,GACnB,CAAC,QAAQ,GAAG,UAAU,CAAC,GACvB,CAAC,QAAQ,GAAG,aAAa,CAAC,GAC1B,CAAC,QAAQ,GAAG,WAAW,CAAC,GACxB,CAAC,QAAQ,GAAG,UAAU,CAAC,GACvB,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AACtB,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAChE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,kBAAkB,GAAG,oBAAoB,GAAG,OAAO,CAAC;AACzE;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACxC,MAAM,MAAM,oBAAoB,GAC5B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAC5D;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC,MAAM,MAAM,mBAAmB,GAC3B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN,MAAM,MAAM,KAAK,GAAG,aAAa,GAAG,eAAe,CAAC;AACpD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AACnC;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AACnE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC,MAAM,MAAM,mBAAmB,GAC3B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,qBAAqB,GAAG,uBAAuB,CAAC;AACxE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC3C;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,eAAe,CAAC;AACvC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,gBAAgB,CAAC;AACzD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAC/C;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAChD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG,yBAAyB,GAAG,iBAAiB,CAAC;AAC3F;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACtC;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AACzC;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC;AACxC;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,kBAAkB,CAAC;AAC1D;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAChC,MAAM,MAAM,kBAAkB,GAC1B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,YAAY,GAAG,cAAc,GAAG,aAAa,CAAC;AACpE;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAClC;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;AACpC;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC;AAClC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AACpC;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AACnC,MAAM,MAAM,eAAe,GACvB;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AACpC,MAAM,MAAM,gBAAgB,GACxB;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AACpE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC1C,MAAM,MAAM,kBAAkB,GAC1B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG,uBAAuB,GAAG,WAAW,CAAC;AACvE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAChC,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAC7C,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC;AAClC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACF;;GAEG;AACH,MAAM,MAAM,KAAK,GACb,CAAC,QAAQ,GAAG,UAAU,CAAC,GACvB,CAAC,QAAQ,GAAG,MAAM,CAAC,GACnB,CAAC,QAAQ,GAAG,KAAK,CAAC,GAClB,CAAC,QAAQ,GAAG,KAAK,CAAC,GAClB,CAAC,QAAQ,GAAG,YAAY,CAAC,GACzB,CAAC,QAAQ,GAAG,SAAS,CAAC,GACtB,CAAC,QAAQ,GAAG,QAAQ,CAAC,GACrB,CAAC,QAAQ,GAAG,KAAK,CAAC,GAClB,CAAC,QAAQ,GAAG,WAAW,CAAC,GACxB,CAAC,QAAQ,GAAG,WAAW,CAAC,GACxB,CAAC,QAAQ,GAAG,OAAO,CAAC,GACpB,CAAC,QAAQ,GAAG,WAAW,CAAC,GACxB,CAAC,QAAQ,GAAG,cAAc,CAAC,GAC3B,CAAC,QAAQ,GAAG,YAAY,CAAC,GACzB,CAAC,QAAQ,GAAG,WAAW,CAAC,GACxB,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC;AACvB,MAAM,MAAM,UAAU,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AACjE;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACxC;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,mBAAmB,GAAG,qBAAqB,GAAG,OAAO,CAAC;AAC3E;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AACzC,MAAM,MAAM,qBAAqB,GAC7B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,kBAAkB,GAAG,oBAAoB,CAAC;AAC9D;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACxC,MAAM,MAAM,oBAAoB,GAC5B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN,MAAM,MAAM,KAAK,GAAG,cAAc,GAAG,gBAAgB,CAAC;AACtD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AACpC;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,kBAAkB,GAAG,oBAAoB,CAAC;AACrE;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACxC,MAAM,MAAM,oBAAoB,GAC5B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,sBAAsB,GAAG,wBAAwB,CAAC;AAC1E;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAC5C;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,gBAAgB,CAAC;AACxC;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAC5D;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAChD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAChD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG,0BAA0B,GAAG,kBAAkB,CAAC;AAC9F;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACvC;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC1C;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAC9B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC;AACzC;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,mBAAmB,CAAC;AAC5D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AACjC,MAAM,MAAM,mBAAmB,GAC3B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,eAAe,GAAG,cAAc,CAAC;AACvE;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AACnC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC;AACrC;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC;AAClC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AACpC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AACpC,MAAM,MAAM,gBAAgB,GACxB;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AACpC,MAAM,MAAM,gBAAgB,GACxB;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,qBAAqB,GAAG,mBAAmB,CAAC;AACtE;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC3C,MAAM,MAAM,mBAAmB,GAC3B;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,GACD;IACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AACN;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,WAAW,GAAG,wBAAwB,GAAG,YAAY,CAAC;AAC1E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AACjC,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAC9C,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC;AACnC;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,eAAe,EAAE,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,4GAA4G,CAAC;IACvH;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC,EAAE,CAAC;IAC5E;;OAEG;IACH,QAAQ,CAAC,EACL,CAAC,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAC5C,OAAO,GACP,CAAC,CAAC,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;CACjE;AACD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,sBAAsB;IACrC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,MAAM;IACrB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,UAAU,CAAC;IACtB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACjC;AACD,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,KAAK,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,KAAK,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,SAAS,CAAC,EAAE;QACV;;WAEG;QACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B;;WAEG;QACH,IAAI,CAAC,EACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,CAAC;KACP,CAAC;CACH;AACD,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,YAAY,CAAC;IAC1B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,SAAS,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,QAAQ,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,YAAY,CAAC;IAC3C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;IACtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC;;OAEG;IACH,gBAAgB,CAAC,EAAE;QACjB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;KACxC,CAAC;IACF;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,WAAW,CAAC;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD,IAAI,CAAC,EAAE,mBAAmB,GAAG,qBAAqB,CAAC;IACnD,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC;AACD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC;IAChB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,WAAW,CAAC;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,WAAW,CAAC;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,cAAc,CAAC;IAC9B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,YAAY,CAAC;IAC1B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,MAAM,EAAE,aAAa,GAAG,eAAe,CAAC;IACxC;;OAEG;IACH,MAAM,EAAE,cAAc,GAAG,gBAAgB,CAAC;IAC1C;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,WAAW,CAAC;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,KAAK,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,QAAQ,GAAG,uBAAuB,CAAC,EAAE,CAAC;IACjD;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AACD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,uBAAuB;IACtC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,UAAU,CAAC;IACtB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACjC;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,KAAK,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,KAAK,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,SAAS,CAAC,EAAE;QACV;;WAEG;QACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B;;WAEG;QACH,IAAI,CAAC,EACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,GACD;YACE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;SACtB,CAAC;KACP,CAAC;CACH;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,YAAY,CAAC;IAC1B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,QAAQ,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,YAAY,CAAC;IAC3C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC;;OAEG;IACH,gBAAgB,CAAC,EAAE;QACjB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;KACxC,CAAC;IACF;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,WAAW,CAAC;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,0BAA0B;IACzC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAChD,IAAI,CAAC,EAAE,oBAAoB,GAAG,sBAAsB,CAAC;IACrD,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;CACxC;AACD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC;IAChB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,WAAW,CAAC;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,WAAW,CAAC;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,cAAc,CAAC;IAC9B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,YAAY,CAAC;IAC1B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,MAAM,EAAE,cAAc,GAAG,gBAAgB,CAAC;IAC1C;;OAEG;IACH,MAAM,EAAE,cAAc,GAAG,gBAAgB,CAAC;IAC1C;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,WAAW,CAAC;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,yGAAyG,CAAC;IACpH;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AACD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,KAAK,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB"} \ No newline at end of file diff --git a/dist/types/generated/test_v3.js b/dist/types/generated/test_v3.js new file mode 100644 index 00000000..386b70db --- /dev/null +++ b/dist/types/generated/test_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from test_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=test_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/test_v3.js.map b/dist/types/generated/test_v3.js.map new file mode 100644 index 00000000..c5482cc2 --- /dev/null +++ b/dist/types/generated/test_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"test_v3.js","sourceRoot":"","sources":["../../../src/types/generated/test_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/type_v3.d.ts b/dist/types/generated/type_v3.d.ts new file mode 100644 index 00000000..072eb793 --- /dev/null +++ b/dist/types/generated/type_v3.d.ts @@ -0,0 +1,54 @@ +/** + * Auto-generated from type_v3.schema.json + * Do not edit manually + */ +/** + * Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`. + */ +export type TypeKeys = TypeKeysSimple | TypeKeysDetailed; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple = string | string[]; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple1 = string | string[]; +export interface TypeKeysDetailed { + keys: TypeKeysSimple1; + /** + * Delay in milliseconds between each key press during a recording + */ + inputDelay?: number; + /** + * Selector for the element to type into. If not specified, the typing occurs in the active element. + */ + selector?: string; + /** + * Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria. + */ + elementText?: string; + /** + * ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementId?: string; + /** + * data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementTestId?: string; + /** + * Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes. + */ + elementClass?: string | string[]; + /** + * Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence. + */ + elementAttribute?: { + [k: string]: string | number | boolean; + }; + /** + * Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementAria?: string; +} +//# sourceMappingURL=type_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/type_v3.d.ts.map b/dist/types/generated/type_v3.d.ts.map new file mode 100644 index 00000000..12e54231 --- /dev/null +++ b/dist/types/generated/type_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"type_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/type_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,gBAAgB,CAAC;AACzD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAC/C;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAEhD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;IACtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC;;OAEG;IACH,gBAAgB,CAAC,EAAE;QACjB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;KACxC,CAAC;IACF;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"} \ No newline at end of file diff --git a/dist/types/generated/type_v3.js b/dist/types/generated/type_v3.js new file mode 100644 index 00000000..61a55f4f --- /dev/null +++ b/dist/types/generated/type_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from type_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=type_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/type_v3.js.map b/dist/types/generated/type_v3.js.map new file mode 100644 index 00000000..ae60ebb7 --- /dev/null +++ b/dist/types/generated/type_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"type_v3.js","sourceRoot":"","sources":["../../../src/types/generated/type_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/types/generated/wait_v3.d.ts b/dist/types/generated/wait_v3.d.ts new file mode 100644 index 00000000..d7ad2ce8 --- /dev/null +++ b/dist/types/generated/wait_v3.d.ts @@ -0,0 +1,12 @@ +/** + * Auto-generated from wait_v3.schema.json + * Do not edit manually + */ +/** + * Pause (in milliseconds) before performing the next action. + */ +export type Wait = WaitSimple | WaitEnvironmentVariable | WaitBoolean; +export type WaitSimple = number; +export type WaitEnvironmentVariable = string; +export type WaitBoolean = boolean; +//# sourceMappingURL=wait_v3.d.ts.map \ No newline at end of file diff --git a/dist/types/generated/wait_v3.d.ts.map b/dist/types/generated/wait_v3.d.ts.map new file mode 100644 index 00000000..e0b2490a --- /dev/null +++ b/dist/types/generated/wait_v3.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"wait_v3.d.ts","sourceRoot":"","sources":["../../../src/types/generated/wait_v3.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,uBAAuB,GAAG,WAAW,CAAC;AACtE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAChC,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAC7C,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC"} \ No newline at end of file diff --git a/dist/types/generated/wait_v3.js b/dist/types/generated/wait_v3.js new file mode 100644 index 00000000..964ec3b2 --- /dev/null +++ b/dist/types/generated/wait_v3.js @@ -0,0 +1,8 @@ +"use strict"; +/* eslint-disable */ +/** + * Auto-generated from wait_v3.schema.json + * Do not edit manually + */ +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=wait_v3.js.map \ No newline at end of file diff --git a/dist/types/generated/wait_v3.js.map b/dist/types/generated/wait_v3.js.map new file mode 100644 index 00000000..4ad1662f --- /dev/null +++ b/dist/types/generated/wait_v3.js.map @@ -0,0 +1 @@ +{"version":3,"file":"wait_v3.js","sourceRoot":"","sources":["../../../src/types/generated/wait_v3.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB;;;GAGG"} \ No newline at end of file diff --git a/dist/validate.d.ts b/dist/validate.d.ts new file mode 100644 index 00000000..f95cd88b --- /dev/null +++ b/dist/validate.d.ts @@ -0,0 +1,41 @@ +export interface ValidateOptions { + schemaKey: string; + object: any; + addDefaults?: boolean; +} +export interface ValidateResult { + valid: boolean; + errors: string; + object: any; +} +export interface TransformOptions { + currentSchema: string; + targetSchema: string; + object: any; +} +/** + * Validates an object against a specified JSON schema, supporting backward compatibility and automatic transformation from older schema versions if needed. + * + * If validation against the target schema fails and compatible older schemas are defined, attempts validation against each compatible schema. On a match, transforms the object to the target schema and revalidates. Returns the validation result, any errors, and the (possibly transformed) object. + * + * @param options - Validation options + * @param options.schemaKey - The key identifying the target JSON schema. + * @param options.object - The object to validate. + * @param options.addDefaults - Whether to include default values in the returned object. + * @returns Validation result, error messages, and the validated (and possibly transformed) object. + * + * @throws {Error} If {@link schemaKey} or {@link object} is missing. + */ +export declare function validate({ schemaKey, object, addDefaults }: ValidateOptions): ValidateResult; +/** + * Transform an object from one schema key to another and return a validated instance of the target schema. + * + * @param params - Function parameters. + * @param params.currentSchema - Schema key representing the object's current version. + * @param params.targetSchema - Schema key to transform the object into. + * @param params.object - The source object to transform. + * @returns The transformed object conforming to the target schema. + * @throws {Error} If transformation between the specified schemas is not supported or if the transformed object fails validation. + */ +export declare function transformToSchemaKey({ currentSchema, targetSchema, object, }: TransformOptions): any; +//# sourceMappingURL=validate.d.ts.map \ No newline at end of file diff --git a/dist/validate.d.ts.map b/dist/validate.d.ts.map new file mode 100644 index 00000000..713de211 --- /dev/null +++ b/dist/validate.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AA0DA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,GAAG,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,GAAG,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,GAAG,CAAC;CACb;AAYD;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,WAAkB,EAAE,EAAE,eAAe,GAAG,cAAc,CA6FnG;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,aAAkB,EAClB,YAAiB,EACjB,MAAW,GACZ,EAAE,gBAAgB,GAAG,GAAG,CA4YxB"} \ No newline at end of file diff --git a/dist/validate.js b/dist/validate.js new file mode 100644 index 00000000..908dde84 --- /dev/null +++ b/dist/validate.js @@ -0,0 +1,542 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.validate = validate; +exports.transformToSchemaKey = transformToSchemaKey; +const schemas_1 = require("./schemas"); +const ajv_1 = __importDefault(require("ajv")); +// Ajv extra formats: https://ajv.js.org/packages/ajv-formats.html +const ajv_formats_1 = __importDefault(require("ajv-formats")); +// Ajv extra keywords: https://ajv.js.org/packages/ajv-keywords.html +const ajv_keywords_1 = __importDefault(require("ajv-keywords")); +// Ajv custom errors: https://ajv.js.org/packages/ajv-errors.html +const ajv_errors_1 = __importDefault(require("ajv-errors")); +const crypto_1 = require("crypto"); +// Configure base Ajv +const ajv = new ajv_1.default({ + strictSchema: false, + useDefaults: true, + allErrors: true, + allowUnionTypes: true, + coerceTypes: true, +}); +// Enable `uuid` dynamic default +// @ts-ignore - ajv-keywords has incomplete types for dynamicDefaults +const def = require("ajv-keywords/dist/definitions/dynamicDefaults"); +def.DEFAULTS.uuid = () => crypto_1.randomUUID; +// Enhance Ajv +(0, ajv_formats_1.default)(ajv); +(0, ajv_keywords_1.default)(ajv); +(0, ajv_errors_1.default)(ajv); +// Add all schemas from `schema` object. +for (const [key, value] of Object.entries(schemas_1.schemas)) { + ajv.addSchema(value, key); +} +const compatibleSchemas = { + config_v3: ["config_v2"], + context_v3: ["context_v2"], + openApi_v3: ["openApi_v2"], + spec_v3: ["spec_v2"], + step_v3: [ + "checkLink_v2", + "find_v2", + "goTo_v2", + "httpRequest_v2", + "runShell_v2", + "runCode_v2", + "saveScreenshot_v2", + "setVariables_v2", + "startRecording_v2", + "stopRecording_v2", + "typeKeys_v2", + "wait_v2", + ], + test_v3: ["test_v2"], +}; +/** + * Escapes special characters in a string for safe use in a regular expression pattern. + * + * @param string - The input string to escape. + * @returns The escaped string, safe for use in regular expressions. + */ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string +} +/** + * Validates an object against a specified JSON schema, supporting backward compatibility and automatic transformation from older schema versions if needed. + * + * If validation against the target schema fails and compatible older schemas are defined, attempts validation against each compatible schema. On a match, transforms the object to the target schema and revalidates. Returns the validation result, any errors, and the (possibly transformed) object. + * + * @param options - Validation options + * @param options.schemaKey - The key identifying the target JSON schema. + * @param options.object - The object to validate. + * @param options.addDefaults - Whether to include default values in the returned object. + * @returns Validation result, error messages, and the validated (and possibly transformed) object. + * + * @throws {Error} If {@link schemaKey} or {@link object} is missing. + */ +function validate({ schemaKey, object, addDefaults = true }) { + if (!schemaKey) { + throw new Error("Schema key is required."); + } + if (!object) { + throw new Error("Object is required."); + } + const result = { + valid: false, + errors: "", + object: object, + }; + let validationObject; + let check = ajv.getSchema(schemaKey); + if (!check) { + result.valid = false; + result.errors = `Schema not found: ${schemaKey}`; + result.object = object; + return result; + } + // Clone the object to avoid modifying the original object + validationObject = JSON.parse(JSON.stringify(object)); + // Check if the object is compatible with the schema + result.valid = check(validationObject); + result.errors = ""; + if (check.errors) { + // Check if the object is compatible with another schema + const compatibleSchemasList = compatibleSchemas[schemaKey]; + if (!compatibleSchemasList) { + result.errors = check.errors + .map((error) => `${error.instancePath} ${error.message} (${JSON.stringify(error.params)})`) + .join(", "); + result.object = object; + result.valid = false; + return result; + } + const matchedSchemaKey = compatibleSchemasList.find((key) => { + validationObject = JSON.parse(JSON.stringify(object)); + const check = ajv.getSchema(key); + if (check && check(validationObject)) + return key; + }); + if (!matchedSchemaKey) { + result.errors = check.errors + .map((error) => `${error.instancePath} ${error.message} (${JSON.stringify(error.params)})`) + .join(", "); + result.object = object; + result.valid = false; + return result; + } + else { + const transformedObject = transformToSchemaKey({ + currentSchema: matchedSchemaKey, + targetSchema: schemaKey, + object: validationObject, + }); + result.valid = check(transformedObject); + if (result.valid) { + validationObject = transformedObject; + object = transformedObject; + /* c8 ignore start - Defensive: transformToSchemaKey validates internally, so this is unreachable */ + } + else if (check.errors) { + const errors = check.errors.map((error) => `${error.instancePath} ${error.message} (${JSON.stringify(error.params)})`); + result.errors = errors.join(", "); + return result; + } + /* c8 ignore stop */ + } + } + if (addDefaults) { + result.object = validationObject; + } + else { + result.object = object; + } + return result; +} +/** + * Transform an object from one schema key to another and return a validated instance of the target schema. + * + * @param params - Function parameters. + * @param params.currentSchema - Schema key representing the object's current version. + * @param params.targetSchema - Schema key to transform the object into. + * @param params.object - The source object to transform. + * @returns The transformed object conforming to the target schema. + * @throws {Error} If transformation between the specified schemas is not supported or if the transformed object fails validation. + */ +function transformToSchemaKey({ currentSchema = "", targetSchema = "", object = {}, }) { + // Check if the current schema is the same as the target schema + if (currentSchema === targetSchema) { + return object; + } + // Check if the current schema is compatible with the target schema + if (!compatibleSchemas[targetSchema]?.includes(currentSchema)) { + throw new Error(`Can't transform from ${currentSchema} to ${targetSchema}.`); + } + // Transform the object + if (targetSchema === "step_v3") { + const transformedObject = { + stepId: object.id, + description: object.description, + }; + if (currentSchema === "goTo_v2") { + transformedObject.goTo = { + url: object.url, + origin: object.origin, + }; + } + else if (currentSchema === "checkLink_v2") { + transformedObject.checkLink = { + url: object.url, + origin: object.origin, + statusCodes: object.statusCodes, + }; + } + else if (currentSchema === "find_v2") { + transformedObject.find = { + selector: object.selector, + elementText: object.matchText, + timeout: object.timeout, + moveTo: object.moveTo, + click: object.click, + type: object.typeKeys, + }; + // Handle typeKeys.delay key change + if (typeof object.typeKeys === "object" && object.typeKeys.keys) { + transformedObject.find.type.inputDelay = object.typeKeys.delay; + delete transformedObject.find.type.delay; + } + transformedObject.variables = {}; + object.setVariables?.forEach((variable) => { + transformedObject.variables[variable.name] = `extract($$element.text, "${variable.regex}")`; + }); + } + else if (currentSchema === "httpRequest_v2") { + transformedObject.httpRequest = { + method: object.method, + url: object.url, + openApi: object.openApi, + request: { + body: object.requestData, + headers: object.requestHeaders, + parameters: object.requestParams, + }, + response: { + body: object.responseData, + headers: object.responseHeaders, + }, + statusCodes: object.statusCodes, + allowAdditionalFields: object.allowAdditionalFields, + timeout: object.timeout, + path: object.savePath, + directory: object.saveDirectory, + maxVariation: object.maxVariation / 100, + overwrite: object.overwrite === "byVariation" + ? "aboveVariation" + : object.overwrite, + }; + // Handle openApi.requestHeaders key change + if (object.openApi) { + transformedObject.httpRequest.openApi = transformToSchemaKey({ + currentSchema: "openApi_v2", + targetSchema: "openApi_v3", + object: object.openApi, + }); + } + transformedObject.variables = {}; + object.envsFromResponseData?.forEach((variable) => { + transformedObject.variables[variable.name] = `jq($$response.body, "${variable.jqFilter}")`; + }); + } + else if (currentSchema === "runShell_v2") { + transformedObject.runShell = { + command: object.command, + args: object.args, + workingDirectory: object.workingDirectory, + exitCodes: object.exitCodes, + stdio: object.output, + path: object.savePath, + directory: object.saveDirectory, + maxVariation: object.maxVariation / 100, + overwrite: object.overwrite === "byVariation" + ? "aboveVariation" + : object.overwrite, + timeout: object.timeout, + }; + transformedObject.variables = {}; + object.setVariables?.forEach((variable) => { + transformedObject.variables[variable.name] = `extract($$stdio.stdout, "${variable.regex}")`; + }); + } + else if (currentSchema === "runCode_v2") { + transformedObject.runCode = { + language: object.language, + code: object.code, + args: object.args, + workingDirectory: object.workingDirectory, + exitCodes: object.exitCodes, + stdio: object.output, + path: object.savePath, + directory: object.saveDirectory, + maxVariation: object.maxVariation / 100, + overwrite: object.overwrite === "byVariation" + ? "aboveVariation" + : object.overwrite, + timeout: object.timeout, + }; + transformedObject.variables = {}; + object?.setVariables?.forEach((variable) => { + transformedObject.variables[variable.name] = `extract($$stdio.stdout, "${variable.regex}")`; + }); + } + else if (currentSchema === "setVariables_v2") { + transformedObject.loadVariables = object.path; + } + else if (currentSchema === "typeKeys_v2") { + transformedObject.type = { + keys: object.keys, + inputDelay: object.delay, + }; + } + else if (currentSchema === "saveScreenshot_v2") { + transformedObject.screenshot = { + path: object.path, + directory: object.directory, + maxVariation: object.maxVariation / 100, + overwrite: object.overwrite === "byVariation" + ? "aboveVariation" + : object.overwrite, + crop: object.crop, + }; + } + else if (currentSchema === "startRecording_v2") { + transformedObject.record = { + path: object.path, + directory: object.directory, + overwrite: object.overwrite, + }; + } + else if (currentSchema === "stopRecording_v2") { + transformedObject.stopRecord = true; + } + else if (currentSchema === "wait_v2") { + transformedObject.wait = object; + } + const result = validate({ + schemaKey: "step_v3", + object: transformedObject, + }); + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } + else if (targetSchema === "config_v3") { + // Handle config_v2 to config_v3 transformation + const transformedObject = { + loadVariables: object.envVariables, + input: object?.runTests?.input || object.input, + output: object?.runTests?.output || object.output, + recursive: object?.runTests?.recursive || object.recursive, + relativePathBase: object.relativePathBase, + detectSteps: object?.runTests?.detectSteps, + beforeAny: object?.runTests?.setup, + afterAll: object?.runTests?.cleanup, + logLevel: object.logLevel, + telemetry: object.telemetry, + }; + // Handle context transformation + if (object?.runTests?.contexts) + transformedObject.runOn = object.runTests.contexts.map((context) => transformToSchemaKey({ + currentSchema: "context_v2", + targetSchema: "context_v3", + object: context, + })); + // Handle openApi transformation + if (object?.integrations?.openApi) { + transformedObject.integrations = {}; + transformedObject.integrations.openApi = object.integrations.openApi.map((description) => transformToSchemaKey({ + currentSchema: "openApi_v2", + targetSchema: "openApi_v3", + object: description, + })); + } + // Handle fileTypes transformation + if (object?.fileTypes) + transformedObject.fileTypes = object.fileTypes.map((fileType) => { + const transformedFileType = { + name: fileType.name, + extensions: fileType.extensions.map((extension) => + // Trim leading `.` from extension + extension.replace(/^\./, "")), + inlineStatements: { + // Convert strings to regex, escaping special characters + testStart: `${escapeRegExp(fileType.testStartStatementOpen)}(.*?)${escapeRegExp(fileType.testStartStatementClose)}`, + testEnd: escapeRegExp(fileType.testEndStatement), + ignoreStart: escapeRegExp(fileType.testIgnoreStatement), + step: `${escapeRegExp(fileType.stepStatementOpen)}(.*?)${escapeRegExp(fileType.stepStatementClose)}`, + }, + }; + if (fileType.markup) + transformedFileType.markup = fileType.markup.map((markup) => { + const transformedMarkup = { + name: markup.name, + regex: markup.regex, + }; + if (markup.actions) + transformedMarkup.actions = markup.actions.map((action) => { + if (typeof action === "string") + return action; + if (typeof action === "object") { + if (action.params) { + action = { + action: action.name, + ...action.params, + }; + } + const transformedAction = transformToSchemaKey({ + currentSchema: `${action.action}_v2`, + targetSchema: "step_v3", + object: action, + }); + return transformedAction; + } + }); + return transformedMarkup; + }); + return transformedFileType; + }); + const result = validate({ + schemaKey: "config_v3", + object: transformedObject, + }); + // Defensive: transformation always produces valid config_v3, unreachable + /* c8 ignore next 3 */ + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } + else if (targetSchema === "context_v3") { + const transformedObject = {}; + // Handle context_v2 to context_v3 transformation + transformedObject.platforms = object.platforms; + if (object.app?.name) { + const name = object.app.name === "edge" ? "chrome" : object.app?.name; + transformedObject.browsers = []; + transformedObject.browsers.push({ + name, + headless: object.app?.options?.headless, + window: { + width: object.app?.options?.width, + height: object.app?.options?.height, + }, + viewport: { + width: object.app?.options?.viewport_width, + height: object.app?.options?.viewport_height, + }, + }); + } + const result = validate({ + schemaKey: "context_v3", + object: transformedObject, + }); + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } + else if (targetSchema === "openApi_v3") { + let transformedObject; + // Handle openApi_v2 to openApi_v3 transformation + const { name, requestHeaders, ...intermediaryObject } = object; + intermediaryObject.name = object.name; + intermediaryObject.headers = object.requestHeaders; + transformedObject = { ...intermediaryObject }; + const result = validate({ + schemaKey: "openApi_v3", + object: transformedObject, + }); + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return transformedObject; + } + else if (targetSchema === "spec_v3") { + // Handle spec_v2 to spec_v3 transformation + const transformedObject = { + specId: object.id, + description: object.description, + contentPath: object.file, + }; + if (object.contexts) + transformedObject.runOn = object.contexts.map((context) => transformToSchemaKey({ + currentSchema: "context_v2", + targetSchema: "context_v3", + object: context, + })); + if (object.openApi) + transformedObject.openApi = object.openApi.map((description) => transformToSchemaKey({ + currentSchema: "openApi_v2", + targetSchema: "openApi_v3", + object: description, + })); + transformedObject.tests = object.tests.map((test) => transformToSchemaKey({ + currentSchema: "test_v2", + targetSchema: "test_v3", + object: test, + })); + const result = validate({ + schemaKey: "spec_v3", + object: transformedObject, + }); + // Defensive: nested transforms validate; this is unreachable + /* c8 ignore next 3 */ + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } + else if (targetSchema === "test_v3") { + // Handle test_v2 to test_v3 transformation + const transformedObject = { + testId: object.id, + description: object.description, + contentPath: object.file, + detectSteps: object.detectSteps, + before: object.setup, + after: object.cleanup, + }; + if (object.contexts) + transformedObject.runOn = object.contexts.map((context) => transformToSchemaKey({ + currentSchema: "context_v2", + targetSchema: "context_v3", + object: context, + })); + if (object.openApi) + transformedObject.openApi = object.openApi.map((description) => transformToSchemaKey({ + currentSchema: "openApi_v2", + targetSchema: "openApi_v3", + object: description, + })); + transformedObject.steps = object.steps.map((step) => transformToSchemaKey({ + currentSchema: `${step.action}_v2`, + targetSchema: "step_v3", + object: step, + })); + const result = validate({ + schemaKey: "test_v3", + object: transformedObject, + }); + // Defensive: nested transforms validate; this is unreachable + /* c8 ignore next 3 */ + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } + /* c8 ignore next - Dead code: incompatible schemas throw at line 197-200 */ + return null; +} +//# sourceMappingURL=validate.js.map \ No newline at end of file diff --git a/dist/validate.js.map b/dist/validate.js.map new file mode 100644 index 00000000..a912309d --- /dev/null +++ b/dist/validate.js.map @@ -0,0 +1 @@ +{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index fd3baeec..75a5884e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,10 +18,13 @@ "yaml": "^2.8.2" }, "devDependencies": { + "@types/node": "^22.10.5", "c8": "^10.1.3", "chai": "^6.2.2", + "json-schema-to-typescript": "^15.0.4", "mocha": "^11.7.5", - "sinon": "^21.0.1" + "sinon": "^21.0.1", + "typescript": "^5.7.3" } }, "node_modules/@apidevtools/json-schema-ref-parser": { @@ -190,6 +193,13 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true, + "license": "MIT" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -255,6 +265,23 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "peer": true }, + "node_modules/@types/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.7.tgz", + "integrity": "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, "node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -684,6 +711,24 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -915,6 +960,16 @@ "dev": true, "license": "MIT" }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -924,6 +979,19 @@ "node": ">=8" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -1029,6 +1097,48 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-schema-to-typescript": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.4.tgz", + "integrity": "sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^11.5.5", + "@types/json-schema": "^7.0.15", + "@types/lodash": "^4.17.7", + "is-glob": "^4.0.3", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "prettier": "^3.2.5", + "tinyglobby": "^0.2.9" + }, + "bin": { + "json2ts": "dist/src/cli.js" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/json-schema-to-typescript/node_modules/@apidevtools/json-schema-ref-parser": { + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.3.tgz", + "integrity": "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -1050,6 +1160,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -1135,6 +1252,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -1297,6 +1424,36 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.0.tgz", + "integrity": "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -1544,6 +1701,23 @@ "node": ">=18" } }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -1554,6 +1728,27 @@ "node": ">=4" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", diff --git a/package.json b/package.json index a06da659..92ccc650 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,20 @@ "name": "doc-detective-common", "version": "3.6.1-dev.1", "description": "Shared components for Doc Detective projects.", - "main": "src/index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.mjs", + "types": "./dist/index.d.ts" + } + }, "scripts": { + "generate:types": "node scripts/generateTypes.js", "dereferenceSchemas": "node ./src/schemas/dereferenceSchemas.js", - "build": "npm run dereferenceSchemas", + "compile": "tsc && node scripts/createEsmWrapper.js", + "build": "npm run dereferenceSchemas && npm run generate:types && npm run compile", "postbuild": "npm run test", "test": "mocha", "test:coverage": "c8 mocha", @@ -24,10 +34,13 @@ }, "homepage": "https://github.com/doc-detective/doc-detective-common#readme", "devDependencies": { + "@types/node": "^22.10.5", "c8": "^10.1.3", "chai": "^6.2.2", + "json-schema-to-typescript": "^15.0.4", "mocha": "^11.7.5", - "sinon": "^21.0.1" + "sinon": "^21.0.1", + "typescript": "^5.7.3" }, "dependencies": { "@apidevtools/json-schema-ref-parser": "^15.1.3", diff --git a/plans/plan-typescriptMigration.prompt.md b/plans/plan-typescriptMigration.prompt.md new file mode 100644 index 00000000..591b75ed --- /dev/null +++ b/plans/plan-typescriptMigration.prompt.md @@ -0,0 +1,25 @@ +## Plan: Incremental TypeScript Migration for doc-detective-common + +A phased approach to convert this CommonJS JavaScript library to TypeScript, leveraging JSON schemas to auto-generate types while maintaining backward compatibility for downstream consumers. + +### Steps + +1. **Set up TypeScript infrastructure** in [package.json](package.json) — add `typescript`, `@types/node`, configure `tsconfig.json` with `declaration: true`, `resolveJsonModule: true`, and dual CJS/ESM output to `dist/` + +2. **Generate TypeScript interfaces from JSON schemas** — use `json-schema-to-typescript` on [output_schemas/](src/schemas/output_schemas) to auto-create types like `StepV3`, `ConfigV3`, `SpecV3` in a new `src/types/generated/` directory + +3. **Convert low-complexity files first** — migrate [src/index.ts](src/index.js) → barrel exports, [src/schemas/index.ts](src/schemas/index.js) → typed schema map, [src/files.ts](src/files.js) → straightforward async function + +4. **Convert medium-complexity** [src/resolvePaths.ts](src/resolvePaths.js) — type the recursive path resolution with discriminated unions for `config` vs `spec` object types and `RelativePathBase` literal types + +5. **Convert high-complexity** [src/validate.ts](src/validate.js) — split 350+ line `transformToSchemaKey()` into modular transformation functions, type the `compatibleSchemas` map, and use generic `validate()` signature + +6. **Update build pipeline** in [dereferenceSchemas.js](src/schemas/dereferenceSchemas.js) — add `tsc` compilation step before schema dereference, update CI workflows to run TypeScript build + +### Further Considerations + +1. **Module system strategy?** Keep CommonJS output for backward compat + add ESM build (recommended) / Switch to pure ESM (breaking change) / Dual-publish with conditional exports + +2. **Schema type generation timing?** Generate types at build time via script (dynamic, adds build step) / Generate once and commit to repo (simpler, requires manual sync) / Use `zod` or `typebox` to replace JSON schemas entirely (major refactor) + +3. **Test migration approach?** Convert tests to TypeScript with `ts-mocha` (full type coverage) / Keep tests as JavaScript importing from `dist/` (faster migration, tests compiled output) / Gradual conversion file-by-file alongside source diff --git a/scripts/createEsmWrapper.js b/scripts/createEsmWrapper.js new file mode 100644 index 00000000..d680826a --- /dev/null +++ b/scripts/createEsmWrapper.js @@ -0,0 +1,21 @@ +const fs = require("fs").promises; +const path = require("path"); + +async function createEsmWrapper() { + const distDir = path.join(__dirname, "..", "dist"); + + // Create ESM wrapper that re-exports from CJS + const esmContent = `// ESM wrapper for CommonJS output +import cjsModule from './index.js'; +export const { schemas, validate, transformToSchemaKey, resolvePaths, readFile } = cjsModule; +export default cjsModule; +`; + + await fs.writeFile(path.join(distDir, "index.mjs"), esmContent); + console.log("Created ESM wrapper at dist/index.mjs"); +} + +createEsmWrapper().catch((error) => { + console.error("Failed to create ESM wrapper:", error); + process.exit(1); +}); diff --git a/scripts/generateTypes.js b/scripts/generateTypes.js new file mode 100644 index 00000000..36ce85fa --- /dev/null +++ b/scripts/generateTypes.js @@ -0,0 +1,45 @@ +const { compile } = require("json-schema-to-typescript"); +const fs = require("fs").promises; +const path = require("path"); + +async function generateTypes() { + const schemasDir = path.join(__dirname, "..", "src", "schemas", "output_schemas"); + const outputDir = path.join(__dirname, "..", "src", "types", "generated"); + + // Create output directory + await fs.mkdir(outputDir, { recursive: true }); + + // Get all v3 schema files (current version) + const files = await fs.readdir(schemasDir); + const v3Schemas = files.filter((f) => f.endsWith("_v3.schema.json")); + + console.log(`Generating TypeScript types for ${v3Schemas.length} schemas...`); + + for (const file of v3Schemas) { + const schemaPath = path.join(schemasDir, file); + const schema = JSON.parse(await fs.readFile(schemaPath, "utf-8")); + + try { + const ts = await compile(schema, schema.title || file.replace(".schema.json", ""), { + bannerComment: `/* eslint-disable */\n/**\n * Auto-generated from ${file}\n * Do not edit manually\n */`, + style: { + semi: true, + trailingComma: "es5", + }, + }); + + const outputPath = path.join(outputDir, file.replace(".schema.json", ".ts")); + await fs.writeFile(outputPath, ts); + console.log(` ✓ ${file} → ${path.basename(outputPath)}`); + } catch (error) { + console.error(` ✗ Failed to generate ${file}:`, error.message); + } + } + + console.log("Type generation complete!"); +} + +generateTypes().catch((error) => { + console.error("Type generation failed:", error); + process.exit(1); +}); diff --git a/src/files.ts b/src/files.ts new file mode 100644 index 00000000..53a0caac --- /dev/null +++ b/src/files.ts @@ -0,0 +1,86 @@ +import * as fs from "fs"; +import * as YAML from "yaml"; +import axios from "axios"; +import { URL } from "url"; + +export interface ReadFileOptions { + fileURLOrPath: string; +} + +/** + * Reads and parses content from a remote URL or local file path, supporting JSON and YAML formats. + * + * Attempts to parse the file content as JSON first, then YAML. If both parsing attempts fail, returns the raw content as a string. Returns `null` if the file cannot be read. + * + * @param options - Options object + * @param options.fileURLOrPath - The URL or local file path to read. + * @returns Parsed object for JSON or YAML files, raw string for other formats, or `null` if reading fails. + * + * @throws {Error} If {@link fileURLOrPath} is missing, not a string, or is an empty string. + */ +export async function readFile({ fileURLOrPath }: ReadFileOptions): Promise { + if (!fileURLOrPath) { + throw new Error("fileURLOrPath is required"); + } + if (typeof fileURLOrPath !== "string") { + throw new Error("fileURLOrPath must be a string"); + } + if (fileURLOrPath.trim() === "") { + throw new Error("fileURLOrPath cannot be an empty string"); + } + + let content: string; + let isRemote = false; + + try { + const parsedURL = new URL(fileURLOrPath); + isRemote = + parsedURL.protocol === "http:" || parsedURL.protocol === "https:"; + } catch (error) { + // Not a valid URL, assume local file path + } + + if (isRemote) { + try { + const response = await axios.get(fileURLOrPath); + content = response.data; + } catch (error) { + console.warn( + `Error reading remote file from ${fileURLOrPath}: ${(error as Error).message}` + ); + return null; + } + } else { + try { + content = await fs.promises.readFile(fileURLOrPath, "utf8"); + } catch (error) { + if ((error as NodeJS.ErrnoException).code === "ENOENT") { + console.warn(`File not found: ${fileURLOrPath}`); + } else { + console.warn(`Error reading file: ${(error as Error).message}`); + } + return null; + } + } + + // Parse based on file extension + const ext = fileURLOrPath.split('.').pop()?.toLowerCase(); + + if (ext === "json") { + try { + return JSON.parse(content); + } catch (error) { + console.warn(`Failed to parse JSON: ${(error as Error).message}`); + return content; + } + } else if (ext === "yaml" || ext === "yml") { + try { + return YAML.parse(content); + } catch (error) { + console.warn(`Failed to parse YAML: ${(error as Error).message}`); + return content; + } + } else { + return content; + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..7988c299 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,4 @@ +export { schemas, SchemaKey, Schema } from "./schemas"; +export { validate, transformToSchemaKey, ValidateOptions, ValidateResult, TransformOptions } from "./validate"; +export { resolvePaths, ResolvePathsOptions } from "./resolvePaths"; +export { readFile, ReadFileOptions } from "./files"; diff --git a/src/resolvePaths.ts b/src/resolvePaths.ts new file mode 100644 index 00000000..9cd6c011 --- /dev/null +++ b/src/resolvePaths.ts @@ -0,0 +1,233 @@ +import * as fs from "fs"; +import * as path from "path"; +import { validate } from "./validate"; + +type RelativePathBase = "file" | "cwd"; +type ObjectType = "config" | "spec"; + +export interface ResolvePathsOptions { + config: { relativePathBase: RelativePathBase }; + object: Record; + filePath: string; + nested?: boolean; + objectType?: ObjectType; +} + +/** + * Convert recognized relative path properties in a config or spec object to absolute paths. + * + * Traverses the provided object (recursing into nested objects and arrays), resolving fields that represent filesystem paths according to the provided config.relativePathBase and reference filePath. On top-level calls the function infers whether the object is a config or spec via schema validation; for nested calls objectType must be provided. + * + * @param options - Options for path resolution. + * @param options.config - Configuration containing settings such as `relativePathBase`. + * @param options.object - The config or spec object whose path properties will be resolved. + * @param options.filePath - Reference file or directory used to resolve relative paths. + * @param options.nested - True when invoked recursively for nested objects. + * @param options.objectType - 'config' or 'spec'; required for nested invocations to select which properties to resolve. + * @returns The same object with applicable path properties converted to absolute paths. + * @throws {Error} If the top-level object matches neither config nor spec schema, or if `objectType` is missing for nested calls. + */ +export async function resolvePaths({ + config, + object, + filePath, + nested = false, + objectType, +}: ResolvePathsOptions): Promise> { + // Config properties that contain paths + const configPaths = [ + "input", + "output", + "loadVariables", + "setup", + "cleanup", + "configPath", + "beforeAny", + "afterAll", + "mediaDirectory", + "downloadDirectory", + "descriptionPath", + "path", + ]; + // Spec properties that contain paths + const specPaths = [ + "file", + "path", + "directory", + "before", + "after", + "loadVariables", + "setup", + "cleanup", + "savePath", + "saveDirectory", + "specPath", + "descriptionPath", + "workingDirectory", + ]; + // Spec objects that are configurable by the user and shouldn't be resolved + const specNoResolve = [ + "requestData", + "responseData", + "requestHeaders", + "responseHeaders", + "requestParams", + "responseParams", + ]; + + /** + * Resolves a relative path to an absolute path using a specified base type and reference file path. + * + * @param baseType - Indicates whether to resolve relative to the reference file's directory ("file") or the current working directory ("cwd"). + * @param relativePath - The path to resolve, which may be relative or absolute. + * @param filePath - The reference file or directory path used for resolution. + * @returns The absolute path corresponding to {@link relativePath}. + * + * @remark If {@link relativePath} is already absolute, it is returned unchanged. If {@link filePath} does not exist, its extension is used to infer whether it is a file or directory. + * @remark HTTP and HTTPS URLs are returned unchanged without resolution. + */ + function resolve(baseType: RelativePathBase, relativePath: string, filePath: string): string { + // If the path is an http:// or https:// URL, or a heretto: URI, return it + if (relativePath.startsWith("https://") || relativePath.startsWith("http://") || relativePath.startsWith("heretto:")) { + return relativePath; + } + + // If path is already absolute, return it + if (path.isAbsolute(relativePath)) { + return relativePath; + } + + // Check if filePath exists and is a file + const fileExists = fs.existsSync(filePath); + const isFile = fileExists + ? fs.lstatSync(filePath).isFile() + : path.parse(filePath).ext !== ""; + + // Use directory of filePath if it's a file (or looks like one) + const basePath = isFile ? path.dirname(filePath) : filePath; + + // Resolve the path based on the base type + return baseType === "file" + ? path.resolve(basePath, relativePath) + : path.resolve(relativePath); + } + + const relativePathBase = config.relativePathBase; + + let pathProperties: string[]; + if (!nested && !objectType) { + // Check if object matches the config schema + const validation = validate({ + schemaKey: "config_v3", + object: { ...object }, + }); + if (validation.valid) { + pathProperties = configPaths; + objectType = "config"; + } else { + // Check if object matches the spec schema + const validation = validate({ + schemaKey: "spec_v3", + object: { ...object }, + }); + if (validation.valid) { + pathProperties = specPaths; + objectType = "spec"; + } else { + throw new Error("Object isn't a valid config or spec."); + } + } + } else if (nested && !objectType) { + // If the object is nested, the object type is required + throw new Error("Object type is required for nested objects."); + } else if (objectType === "config") { + // If the object type is config, use configPaths + pathProperties = configPaths; + } else if (objectType === "spec") { + // If the object type is spec, use specPaths + pathProperties = specPaths; + } else { + throw new Error("Invalid objectType"); + } + + // If the object is null or empty, return it as is + if (object === null || Object.keys(object).length === 0) { + return object; + } + + for (const property of Object.keys(object)) { + // If the property is an array, recursively call resolvePaths for each item in the array + if (Array.isArray(object[property])) { + for (let i = 0; i < object[property].length; i++) { + const item = object[property][i]; + + // If the item is an object, recursively call resolvePaths to resolve paths within the object + if (typeof item === "object") { + await resolvePaths({ + config: config, + object: item, + filePath: filePath, + nested: true, + objectType: objectType, + }); + } else if ( + typeof item === "string" && + pathProperties.includes(property) + ) { + // Resolve the string path and write it back into the array + const resolved = + property === "path" && + object.directory && + path.isAbsolute(object.directory) + ? resolve(relativePathBase, item, object.directory) + : resolve(relativePathBase, item, filePath); + object[property][i] = resolved; + } + } + } + // If the property is an object, recursively call resolvePaths to resolve paths within the object + else if ( + typeof object[property] === "object" && + ((objectType === "spec" && !specNoResolve.includes(property)) || + objectType === "config") + ) { + // If the property is an object, recursively call resolvePaths to resolve paths within the object + object[property] = await resolvePaths({ + config: config, + object: object[property], + filePath: filePath, + nested: true, + objectType: objectType, + }); + } else if (typeof object[property] === "string") { + // If the property begins with "https://", "http://", or "heretto:", skip it + if ( + object[property].startsWith("https://") || + object[property].startsWith("http://") || + object[property].startsWith("heretto:") + ) { + continue; + } + // Check if it matches any of the path properties and resolve it if it does + if (pathProperties.includes(property)) { + if (property === "path" && object.directory) { + const directory = path.isAbsolute(object.directory) + ? object.directory + : resolve(relativePathBase, object.directory, filePath); + object[property] = resolve( + relativePathBase, + object[property], + directory + ); + } else { + object[property] = resolve( + relativePathBase, + object[property], + filePath + ); + } + } + } + } + return object; +} diff --git a/src/schemas/index.ts b/src/schemas/index.ts new file mode 100644 index 00000000..60b5bf5f --- /dev/null +++ b/src/schemas/index.ts @@ -0,0 +1,6 @@ +import schemasJson from "./schemas.json"; + +export type SchemaKey = keyof typeof schemasJson; +export type Schema = (typeof schemasJson)[SchemaKey]; + +export const schemas: typeof schemasJson = schemasJson; diff --git a/src/types/generated/checkLink_v3.ts b/src/types/generated/checkLink_v3.ts new file mode 100644 index 00000000..bf241cd9 --- /dev/null +++ b/src/types/generated/checkLink_v3.ts @@ -0,0 +1,29 @@ +/* eslint-disable */ +/** + * Auto-generated from checkLink_v3.schema.json + * Do not edit manually + */ + +export type CheckLink = CheckLinkDetailed | CheckLinkDetailed1; +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export type CheckLinkDetailed = string; + +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export interface CheckLinkDetailed1 { + /** + * URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. + */ + statusCodes?: number | number[]; +} diff --git a/src/types/generated/click_v3.ts b/src/types/generated/click_v3.ts new file mode 100644 index 00000000..aaf12467 --- /dev/null +++ b/src/types/generated/click_v3.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +/** + * Auto-generated from click_v3.schema.json + * Do not edit manually + */ + +/** + * Click or tap an element. + */ +export type Click = ClickElementSimple | ClickElementDetailed | boolean; +/** + * Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type ClickElementSimple = string; +export type ClickElementDetailed = { + [k: string]: unknown; +}; diff --git a/src/types/generated/config_v3.ts b/src/types/generated/config_v3.ts new file mode 100644 index 00000000..b1bb53cb --- /dev/null +++ b/src/types/generated/config_v3.ts @@ -0,0 +1,405 @@ +/* eslint-disable */ +/** + * Auto-generated from config_v3.schema.json + * Do not edit manually + */ + +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables = string; +export type FileTypePredefined = "markdown" | "asciidoc" | "html" | "dita"; +export type FileTypeCustom = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Perform a native shell command. + */ +export type RunShell = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +}; +/** + * Configuration for Heretto CMS integrations. Each entry specifies a Heretto instance and a scenario to build and test. + */ +export type HerettoCMSIntegrations = HerettoCMSIntegration[]; + +/** + * Configuration options for Doc Detective operations. + */ +export interface Config { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/config_v3.schema.json"; + /** + * Identifier for the configuration. + */ + configId?: string; + /** + * Path to the configuration file. + */ + configPath?: string; + /** + * Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files. + */ + input?: string | [string, ...string[]]; + /** + * Path of the directory in which to store the output of Doc Detective commands. If a file path is specified, Doc Detective attempts to honor the file name specified, but file path behavior is controlled by the configured reporters. + */ + output?: string; + /** + * If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specifications and source files. + */ + recursive?: boolean; + /** + * Whether paths should be interpreted as relative to the current working directory (`cwd`) or to the file in which they're specified (`file`). + */ + relativePathBase?: "cwd" | "file"; + loadVariables?: LoadVariables; + /** + * Default protocol and domain to use for relative URLs. + */ + origin?: string; + /** + * Path(s) to test specifications to perform before those specified by `input`. Useful for setting up testing environments. + */ + beforeAny?: string | string[]; + /** + * Path(s) to test specifications to perform after those specified by `input`. Useful for cleaning up testing environments. + */ + afterAll?: string | string[]; + /** + * Whether or not to detect steps in input files based on defined markup. + */ + detectSteps?: boolean; + /** + * Whether or not to run potentially unsafe steps, such as those that might modify files or system state. + */ + allowUnsafeSteps?: boolean; + /** + * If `true`, crawls sitemap.xml files specified by URL to find additional files to test. + */ + crawl?: boolean; + /** + * If `true`, processes DITA maps and includes generated files as inputs. + */ + processDitaMaps?: boolean; + /** + * Amount of detail to output when performing an operation. + */ + logLevel?: "silent" | "error" | "warning" | "info" | "debug"; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + /** + * Configuration for file types and their markup detection. + */ + fileTypes?: [ + FileTypePredefined | FileTypeCustom | FileTypeExecutable, + ...(FileTypePredefined | FileTypeCustom | FileTypeExecutable)[], + ]; + integrations?: IntegrationsOptions; + telemetry?: TelemetryOptions; + /** + * Number of concurrent test runners. Set to true to use CPU core count (capped at 4). + */ + concurrentRunners?: number | boolean; + environment?: EnvironmentDetails; + /** + * Enable debugging mode. `true` allows pausing on breakpoints, waiting for user input before continuing. `stepThrough` pauses at every step, waiting for user input before continuing. `false` disables all debugging. + */ + debug?: boolean | "stepThrough"; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: + | ("chrome" | "firefox" | "safari" | "webkit") + | Browser + | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface FileTypeExecutable { + /** + * File extensions to use with type. + */ + extensions: string | [string, ...string[]]; + /** + * `runShell` step to perform for this file type. Use $1 as a placeholder for the file path. + */ + runShell?: RunShell; + [k: string]: unknown; +} +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +/** + * Options for connecting to external services. + */ +export interface IntegrationsOptions { + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + docDetectiveApi?: DocDetectiveOrchestrationAPI; + heretto?: HerettoCMSIntegrations; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} +/** + * Configuration for Doc Detective Orchestration API integration. + */ +export interface DocDetectiveOrchestrationAPI { + /** + * API key for authenticating with the Doc Detective Orchestration API. + */ + apiKey?: string; +} +export interface HerettoCMSIntegration { + /** + * Unique identifier for this Heretto integration. Used in logs and results. + */ + name: string; + /** + * The organization subdomain used to access Heretto CCMS (e.g., 'thunderbird' for thunderbird.heretto.com). + */ + organizationId: string; + /** + * Heretto CCMS username (email address) for API authentication. + */ + username: string; + /** + * API token generated in Heretto CCMS for authentication. See https://help.heretto.com/en/heretto-ccms/api/ccms-api-authentication/basic-authentication#ariaid-title3 + */ + apiToken: string; + /** + * Name of the scenario to build and test. + */ + scenarioName?: string; + /** + * Local path where Heretto content was downloaded. Set automatically during processing. + */ + outputPath?: string; + /** + * Mapping of local file paths to Heretto file metadata. Set automatically during content loading. + */ + fileMapping?: { + [k: string]: { + /** + * The UUID of the file in Heretto. + */ + fileId?: string; + /** + * The path of the file in Heretto. + */ + filePath?: string; + [k: string]: unknown; + }; + }; + /** + * If `true`, uploads changed screenshots and other media files back to Heretto CMS after test execution. + */ + uploadOnChange?: boolean; + /** + * Mapping of Heretto file paths to their UUIDs and metadata. Set automatically during content loading by fetching ditamap resource dependencies. + */ + resourceDependencies?: { + [k: string]: { + /** + * The UUID of the file in Heretto. + */ + uuid?: string; + /** + * The full xmldb path of the file in Heretto. + */ + fullPath?: string; + /** + * The file name. + */ + name?: string; + /** + * The UUID of the parent folder in Heretto. + */ + parentFolderId?: string; + [k: string]: unknown; + }; + }; +} +/** + * Options around sending telemetry for Doc Detective usage. + */ +export interface TelemetryOptions { + /** + * If `true`, sends Doc Detective telemetry. + */ + send: boolean; + /** + * Identifier for the organization, group, or individual running Doc Detective. + */ + userId?: string; +} +/** + * Environment information for the system running Doc Detective. + */ +export interface EnvironmentDetails { + /** + * The current working directory of the process running Doc Detective. + */ + workingDirectory?: string; + /** + * The operating system type running Doc Detective. + */ + platform: "linux" | "mac" | "windows"; + /** + * The processor architecture of the system running Doc Detective. + */ + arch?: "arm32" | "arm64" | "x32" | "x64"; +} diff --git a/src/types/generated/context_v3.ts b/src/types/generated/context_v3.ts new file mode 100644 index 00000000..d9fa4a22 --- /dev/null +++ b/src/types/generated/context_v3.ts @@ -0,0 +1,112 @@ +/* eslint-disable */ +/** + * Auto-generated from context_v3.schema.json + * Do not edit manually + */ + +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: + | ("chrome" | "firefox" | "safari" | "webkit") + | Browser + | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} diff --git a/src/types/generated/dragAndDrop_v3.ts b/src/types/generated/dragAndDrop_v3.ts new file mode 100644 index 00000000..43261834 --- /dev/null +++ b/src/types/generated/dragAndDrop_v3.ts @@ -0,0 +1,39 @@ +/* eslint-disable */ +/** + * Auto-generated from dragAndDrop_v3.schema.json + * Do not edit manually + */ + +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple = string; +export type ElementDetailed = { + [k: string]: unknown; +}; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple1 = string; +export type ElementDetailed1 = { + [k: string]: unknown; +}; + +/** + * Drag and drop an element from source to target. + */ +export interface DragAndDrop { + /** + * The element to drag. + */ + source: ElementSimple | ElementDetailed; + /** + * The target location to drop the element. + */ + target: ElementSimple1 | ElementDetailed1; + /** + * Duration of the drag operation in milliseconds. + */ + duration?: number; + [k: string]: unknown; +} diff --git a/src/types/generated/endRecord_v3.ts b/src/types/generated/endRecord_v3.ts new file mode 100644 index 00000000..195f760b --- /dev/null +++ b/src/types/generated/endRecord_v3.ts @@ -0,0 +1,10 @@ +/* eslint-disable */ +/** + * Auto-generated from endRecord_v3.schema.json + * Do not edit manually + */ + +/** + * Stop the current recording. + */ +export type EndRecord = boolean; diff --git a/src/types/generated/find_v3.ts b/src/types/generated/find_v3.ts new file mode 100644 index 00000000..23e80fec --- /dev/null +++ b/src/types/generated/find_v3.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +/** + * Auto-generated from find_v3.schema.json + * Do not edit manually + */ + +/** + * Find an element based on display text or a selector, then optionally interact with it. + */ +export type Find = FindElementSimple | FindElementDetailed; +/** + * Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type FindElementSimple = string; +export type FindElementDetailed = { + [k: string]: unknown; +}; diff --git a/src/types/generated/goTo_v3.ts b/src/types/generated/goTo_v3.ts new file mode 100644 index 00000000..bb89e56e --- /dev/null +++ b/src/types/generated/goTo_v3.ts @@ -0,0 +1,48 @@ +/* eslint-disable */ +/** + * Auto-generated from goTo_v3.schema.json + * Do not edit manually + */ + +export type GoTo = GoToURLSimple | GoToURLDetailed; +/** + * Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any. + */ +export type GoToURLSimple = string; + +/** + * Navigate to an HTTP or HTTPS URL. + */ +export interface GoToURLDetailed { + /** + * URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails. + */ + timeout?: number; + /** + * Configuration for waiting conditions after navigation. + */ + waitUntil?: { + /** + * Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check. + */ + networkIdleTime?: number | null; + /** + * Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check. + */ + domIdleTime?: number | null; + /** + * Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified. + */ + find?: { + [k: string]: unknown; + }; + }; +} diff --git a/src/types/generated/httpRequest_v3.ts b/src/types/generated/httpRequest_v3.ts new file mode 100644 index 00000000..a7686566 --- /dev/null +++ b/src/types/generated/httpRequest_v3.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +/** + * Auto-generated from httpRequest_v3.schema.json + * Do not edit manually + */ + +/** + * Perform a generic HTTP request, for example to an API. + */ +export type HttpRequest = HTTPRequestSimple | HTTPRequestDetailed; +/** + * URL for the HTTP request. + */ +export type HTTPRequestSimple = string; +export type HTTPRequestDetailed = { + [k: string]: unknown; +}; diff --git a/src/types/generated/loadCookie_v3.ts b/src/types/generated/loadCookie_v3.ts new file mode 100644 index 00000000..3c80dfef --- /dev/null +++ b/src/types/generated/loadCookie_v3.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +/** + * Auto-generated from loadCookie_v3.schema.json + * Do not edit manually + */ + +/** + * Load a specific cookie from a file or environment variable into the browser. + */ +export type LoadCookie = CookieNameOrFilePath | LoadCookieDetailed; +/** + * Name of the specific cookie to load from default location, or file path to cookie file. + */ +export type CookieNameOrFilePath = string; +export type LoadCookieDetailed = { + [k: string]: unknown; +}; diff --git a/src/types/generated/loadVariables_v3.ts b/src/types/generated/loadVariables_v3.ts new file mode 100644 index 00000000..786408ee --- /dev/null +++ b/src/types/generated/loadVariables_v3.ts @@ -0,0 +1,10 @@ +/* eslint-disable */ +/** + * Auto-generated from loadVariables_v3.schema.json + * Do not edit manually + */ + +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables = string; diff --git a/src/types/generated/openApi_v3.ts b/src/types/generated/openApi_v3.ts new file mode 100644 index 00000000..3e6a38e0 --- /dev/null +++ b/src/types/generated/openApi_v3.ts @@ -0,0 +1,64 @@ +/* eslint-disable */ +/** + * Auto-generated from openApi_v3.schema.json + * Do not edit manually + */ + +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +} & { + /** + * Name of the OpenAPI description, as defined in your configuration. + */ + name?: string; + /** + * URL or local path to the OpenAPI description. + */ + descriptionPath?: string; + definition?: OpenAPIDefinition; + /** + * ID of the operation to use for the request. + */ + operationId?: string; + /** + * Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI description. + */ + server?: string; + /** + * Validates the request and/or response against the schema in the OpenAPI description. If the request or response doesn't match the schema, the step fails. + */ + validateAgainstSchema?: "request" | "response" | "both" | "none"; + /** + * If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI description as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code. + */ + mockResponse?: boolean; + /** + * Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified. + */ + statusCode?: number; + /** + * Uses the example from the OpenAPI description as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified. + */ + useExample?: "request" | "response" | "both" | "none"; + /** + * Key of the example to use from the `examples` property in the OpenAPI description. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used. + */ + exampleKey?: string; + headers?: OpenAPIRequestHeaders; +}; + +/** + * OpenAPI definition object loaded from the `descriptionPath`. This is a resolved version of the OpenAPI description and should not be user-defined. + */ +export interface OpenAPIDefinition { + [k: string]: unknown; +} +/** + * Request headers to add to requests. For example, to set `Authorization` headers for all requests from the specified OpenAPI document. If specified in both a config and a step, the step value overrides the config value. + */ +export interface OpenAPIRequestHeaders { + [k: string]: string; +} diff --git a/src/types/generated/record_v3.ts b/src/types/generated/record_v3.ts new file mode 100644 index 00000000..b788b15c --- /dev/null +++ b/src/types/generated/record_v3.ts @@ -0,0 +1,34 @@ +/* eslint-disable */ +/** + * Auto-generated from record_v3.schema.json + * Do not edit manually + */ + +/** + * Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ] + */ +export type Record = RecordSimple | RecordDetailed | RecordBoolean; +/** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ +export type RecordSimple = string; +/** + * If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport. + */ +export type RecordBoolean = boolean; + +export interface RecordDetailed { + /** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ + path?: string; + /** + * Directory of the file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * If `true`, overwrites the existing recording at `path` if it exists. + */ + overwrite?: "true" | "false"; + [k: string]: unknown; +} diff --git a/src/types/generated/report_v3.ts b/src/types/generated/report_v3.ts new file mode 100644 index 00000000..bee72783 --- /dev/null +++ b/src/types/generated/report_v3.ts @@ -0,0 +1,183 @@ +/* eslint-disable */ +/** + * Auto-generated from report_v3.schema.json + * Do not edit manually + */ + +/** + * OpenAPI description and configuration. + */ +export type OpenApi = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * A Doc Detective test. + */ +export type Test = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; + +export interface Report { + /** + * Unique identifier for the test specification. + */ + reportId?: string; + /** + * Test specifications that were performed. + * + * @minItems 1 + */ + specs: [Specification, ...Specification[]]; + [k: string]: unknown; +} +export interface Specification { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/spec_v3.schema.json"; + /** + * Unique identifier for the test specification. + */ + specId?: string; + /** + * Description of the test specification. + */ + description?: string; + /** + * Path to the test specification. + */ + specPath?: string; + /** + * Path to the content that the specification is associated with. + */ + contentPath?: string; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + /** + * [Tests](test) to perform. + * + * @minItems 1 + */ + tests: [Test, ...Test[]]; + [k: string]: unknown; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: + | ("chrome" | "firefox" | "safari" | "webkit") + | Browser + | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} diff --git a/src/types/generated/resolvedTests_v3.ts b/src/types/generated/resolvedTests_v3.ts new file mode 100644 index 00000000..9e59ad3c --- /dev/null +++ b/src/types/generated/resolvedTests_v3.ts @@ -0,0 +1,585 @@ +/* eslint-disable */ +/** + * Auto-generated from resolvedTests_v3.schema.json + * Do not edit manually + */ + +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables = string; +export type FileTypePredefined = "markdown" | "asciidoc" | "html" | "dita"; +export type FileTypeCustom = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Perform a native shell command. + */ +export type RunShell = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +}; +/** + * Configuration for Heretto CMS integrations. Each entry specifies a Heretto instance and a scenario to build and test. + */ +export type HerettoCMSIntegrations = HerettoCMSIntegration[]; +/** + * OpenAPI description and configuration. + */ +export type OpenApi1 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * A Doc Detective test. + */ +export type Test = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; + +/** + * A collection of resolved tests ready to be performed. + */ +export interface ResolvedTests { + /** + * Unique identifier for the resolved tests. + */ + resolvedTestsId?: string; + config?: Config; + /** + * Test specifications that were performed. + * + * @minItems 1 + */ + specs: [Specification, ...Specification[]]; + [k: string]: unknown; +} +/** + * Configuration options for Doc Detective operations. + */ +export interface Config { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/config_v3.schema.json"; + /** + * Identifier for the configuration. + */ + configId?: string; + /** + * Path to the configuration file. + */ + configPath?: string; + /** + * Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files. + */ + input?: string | [string, ...string[]]; + /** + * Path of the directory in which to store the output of Doc Detective commands. If a file path is specified, Doc Detective attempts to honor the file name specified, but file path behavior is controlled by the configured reporters. + */ + output?: string; + /** + * If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specifications and source files. + */ + recursive?: boolean; + /** + * Whether paths should be interpreted as relative to the current working directory (`cwd`) or to the file in which they're specified (`file`). + */ + relativePathBase?: "cwd" | "file"; + loadVariables?: LoadVariables; + /** + * Default protocol and domain to use for relative URLs. + */ + origin?: string; + /** + * Path(s) to test specifications to perform before those specified by `input`. Useful for setting up testing environments. + */ + beforeAny?: string | string[]; + /** + * Path(s) to test specifications to perform after those specified by `input`. Useful for cleaning up testing environments. + */ + afterAll?: string | string[]; + /** + * Whether or not to detect steps in input files based on defined markup. + */ + detectSteps?: boolean; + /** + * Whether or not to run potentially unsafe steps, such as those that might modify files or system state. + */ + allowUnsafeSteps?: boolean; + /** + * If `true`, crawls sitemap.xml files specified by URL to find additional files to test. + */ + crawl?: boolean; + /** + * If `true`, processes DITA maps and includes generated files as inputs. + */ + processDitaMaps?: boolean; + /** + * Amount of detail to output when performing an operation. + */ + logLevel?: "silent" | "error" | "warning" | "info" | "debug"; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + /** + * Configuration for file types and their markup detection. + */ + fileTypes?: [ + FileTypePredefined | FileTypeCustom | FileTypeExecutable, + ...(FileTypePredefined | FileTypeCustom | FileTypeExecutable)[], + ]; + integrations?: IntegrationsOptions; + telemetry?: TelemetryOptions; + /** + * Number of concurrent test runners. Set to true to use CPU core count (capped at 4). + */ + concurrentRunners?: number | boolean; + environment?: EnvironmentDetails; + /** + * Enable debugging mode. `true` allows pausing on breakpoints, waiting for user input before continuing. `stepThrough` pauses at every step, waiting for user input before continuing. `false` disables all debugging. + */ + debug?: boolean | "stepThrough"; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: + | ("chrome" | "firefox" | "safari" | "webkit") + | Browser + | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface FileTypeExecutable { + /** + * File extensions to use with type. + */ + extensions: string | [string, ...string[]]; + /** + * `runShell` step to perform for this file type. Use $1 as a placeholder for the file path. + */ + runShell?: RunShell; + [k: string]: unknown; +} +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +/** + * Options for connecting to external services. + */ +export interface IntegrationsOptions { + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + docDetectiveApi?: DocDetectiveOrchestrationAPI; + heretto?: HerettoCMSIntegrations; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} +/** + * Configuration for Doc Detective Orchestration API integration. + */ +export interface DocDetectiveOrchestrationAPI { + /** + * API key for authenticating with the Doc Detective Orchestration API. + */ + apiKey?: string; +} +export interface HerettoCMSIntegration { + /** + * Unique identifier for this Heretto integration. Used in logs and results. + */ + name: string; + /** + * The organization subdomain used to access Heretto CCMS (e.g., 'thunderbird' for thunderbird.heretto.com). + */ + organizationId: string; + /** + * Heretto CCMS username (email address) for API authentication. + */ + username: string; + /** + * API token generated in Heretto CCMS for authentication. See https://help.heretto.com/en/heretto-ccms/api/ccms-api-authentication/basic-authentication#ariaid-title3 + */ + apiToken: string; + /** + * Name of the scenario to build and test. + */ + scenarioName?: string; + /** + * Local path where Heretto content was downloaded. Set automatically during processing. + */ + outputPath?: string; + /** + * Mapping of local file paths to Heretto file metadata. Set automatically during content loading. + */ + fileMapping?: { + [k: string]: { + /** + * The UUID of the file in Heretto. + */ + fileId?: string; + /** + * The path of the file in Heretto. + */ + filePath?: string; + [k: string]: unknown; + }; + }; + /** + * If `true`, uploads changed screenshots and other media files back to Heretto CMS after test execution. + */ + uploadOnChange?: boolean; + /** + * Mapping of Heretto file paths to their UUIDs and metadata. Set automatically during content loading by fetching ditamap resource dependencies. + */ + resourceDependencies?: { + [k: string]: { + /** + * The UUID of the file in Heretto. + */ + uuid?: string; + /** + * The full xmldb path of the file in Heretto. + */ + fullPath?: string; + /** + * The file name. + */ + name?: string; + /** + * The UUID of the parent folder in Heretto. + */ + parentFolderId?: string; + [k: string]: unknown; + }; + }; +} +/** + * Options around sending telemetry for Doc Detective usage. + */ +export interface TelemetryOptions { + /** + * If `true`, sends Doc Detective telemetry. + */ + send: boolean; + /** + * Identifier for the organization, group, or individual running Doc Detective. + */ + userId?: string; +} +/** + * Environment information for the system running Doc Detective. + */ +export interface EnvironmentDetails { + /** + * The current working directory of the process running Doc Detective. + */ + workingDirectory?: string; + /** + * The operating system type running Doc Detective. + */ + platform: "linux" | "mac" | "windows"; + /** + * The processor architecture of the system running Doc Detective. + */ + arch?: "arm32" | "arm64" | "x32" | "x64"; +} +export interface Specification { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/spec_v3.schema.json"; + /** + * Unique identifier for the test specification. + */ + specId?: string; + /** + * Description of the test specification. + */ + description?: string; + /** + * Path to the test specification. + */ + specPath?: string; + /** + * Path to the content that the specification is associated with. + */ + contentPath?: string; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context1[]; + openApi?: (OpenApi1 & OpenAPIDescriptionTest1)[]; + /** + * [Tests](test) to perform. + * + * @minItems 1 + */ + tests: [Test, ...Test[]]; + [k: string]: unknown; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context1 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: + | ("chrome" | "firefox" | "safari" | "webkit") + | Browser2 + | (("chrome" | "firefox" | "safari" | "webkit") | Browser3)[]; +} +/** + * Browser configuration. + */ +export interface Browser2 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow2; + viewport?: BrowserViewport2; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow2 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport2 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser3 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow3; + viewport?: BrowserViewport3; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow3 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport3 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest1 { + [k: string]: unknown; +} diff --git a/src/types/generated/runCode_v3.ts b/src/types/generated/runCode_v3.ts new file mode 100644 index 00000000..dbfada55 --- /dev/null +++ b/src/types/generated/runCode_v3.ts @@ -0,0 +1,59 @@ +/* eslint-disable */ +/** + * Auto-generated from runCode_v3.schema.json + * Do not edit manually + */ + +/** + * Assemble and run code. + */ +export type RunCode = RunCodeDetailed; + +export interface RunCodeDetailed { + /** + * Language of the code to run. + */ + language: "python" | "bash" | "javascript"; + /** + * Code to run. + */ + code: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; + [k: string]: unknown; +} diff --git a/src/types/generated/runShell_v3.ts b/src/types/generated/runShell_v3.ts new file mode 100644 index 00000000..e7cc1af4 --- /dev/null +++ b/src/types/generated/runShell_v3.ts @@ -0,0 +1,58 @@ +/* eslint-disable */ +/** + * Auto-generated from runShell_v3.schema.json + * Do not edit manually + */ + +/** + * Perform a native shell command. + */ +export type RunShell = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; + +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} diff --git a/src/types/generated/saveCookie_v3.ts b/src/types/generated/saveCookie_v3.ts new file mode 100644 index 00000000..058b97af --- /dev/null +++ b/src/types/generated/saveCookie_v3.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +/** + * Auto-generated from saveCookie_v3.schema.json + * Do not edit manually + */ + +/** + * Save a specific browser cookie to a file or environment variable for later reuse. + */ +export type SaveCookie = CookieName | SaveCookieDetailed; +/** + * Name of the specific cookie to save. Will be saved to a default file path or environment variable. + */ +export type CookieName = string; +export type SaveCookieDetailed = { + [k: string]: unknown; +}; diff --git a/src/types/generated/screenshot_v3.ts b/src/types/generated/screenshot_v3.ts new file mode 100644 index 00000000..e7a1d19d --- /dev/null +++ b/src/types/generated/screenshot_v3.ts @@ -0,0 +1,76 @@ +/* eslint-disable */ +/** + * Auto-generated from screenshot_v3.schema.json + * Do not edit manually + */ + +/** + * Takes a screenshot in PNG format. + */ +export type Screenshot = ScreenshotSimple | CaptureScreenshotDetailed | CaptureScreenshot; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple = string; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple1 = string; +/** + * Display text or selector of the element to screenshot. + */ +export type CropByElementSimple = string; +/** + * Crop the screenshot to a specific element. + */ +export type CropByElementDetailed = { + [k: string]: unknown; +}; +/** + * If `true`, captures a screenshot. If `false`, doesn't capture a screenshot. + */ +export type CaptureScreenshot = boolean; + +export interface CaptureScreenshotDetailed { + path?: ScreenshotSimple1; + /** + * Directory of the PNG file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing screenshot at `path` if it exists. + * If `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + crop?: CropByElementSimple | CropByElementDetailed; + sourceIntegration?: SourceIntegration; +} +/** + * Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations. + */ +export interface SourceIntegration { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} diff --git a/src/types/generated/sourceIntegration_v3.ts b/src/types/generated/sourceIntegration_v3.ts new file mode 100644 index 00000000..f991d596 --- /dev/null +++ b/src/types/generated/sourceIntegration_v3.ts @@ -0,0 +1,31 @@ +/* eslint-disable */ +/** + * Auto-generated from sourceIntegration_v3.schema.json + * Do not edit manually + */ + +/** + * Information about the source integration for a file, enabling upload of changed files back to the source CMS. + */ +export interface SourceIntegration { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} diff --git a/src/types/generated/spec_v3.ts b/src/types/generated/spec_v3.ts new file mode 100644 index 00000000..3e975c44 --- /dev/null +++ b/src/types/generated/spec_v3.ts @@ -0,0 +1,166 @@ +/* eslint-disable */ +/** + * Auto-generated from spec_v3.schema.json + * Do not edit manually + */ + +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +}; +/** + * A Doc Detective test. + */ +export type Test = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; + +export interface Specification { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/spec_v3.schema.json"; + /** + * Unique identifier for the test specification. + */ + specId?: string; + /** + * Description of the test specification. + */ + description?: string; + /** + * Path to the test specification. + */ + specPath?: string; + /** + * Path to the content that the specification is associated with. + */ + contentPath?: string; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + /** + * [Tests](test) to perform. + * + * @minItems 1 + */ + tests: [Test, ...Test[]]; + [k: string]: unknown; +} +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: + | ("chrome" | "firefox" | "safari" | "webkit") + | Browser + | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} diff --git a/src/types/generated/step_v3.ts b/src/types/generated/step_v3.ts new file mode 100644 index 00000000..97b0371b --- /dev/null +++ b/src/types/generated/step_v3.ts @@ -0,0 +1,1288 @@ +/* eslint-disable */ +/** + * Auto-generated from step_v3.schema.json + * Do not edit manually + */ + +/** + * A step in a test. + */ +export type Step = + | (Common & CheckLink) + | (Common1 & Click) + | (Common2 & Find) + | (Common3 & GoTo) + | (Common4 & HttpRequest) + | (Common5 & RunShell) + | (Common6 & RunCode) + | (Common7 & Type) + | (Common8 & Screenshot) + | (Common9 & SaveCookie) + | (Common10 & Record) + | (Common11 & StopRecord) + | (Common12 & LoadVariables) + | (Common13 & DragAndDrop) + | (Common14 & LoadCookie) + | (Common15 & Wait); +export type CheckLink1 = CheckLinkDetailed | CheckLinkDetailed1; +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export type CheckLinkDetailed = string; +/** + * Click or tap an element. + */ +export type Click1 = ClickElementSimple | ClickElementDetailed | boolean; +/** + * Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type ClickElementSimple = string; +export type ClickElementDetailed = { + [k: string]: unknown; +}; +/** + * Find an element based on display text or a selector, then optionally interact with it. + */ +export type Find1 = FindElementSimple | FindElementDetailed; +/** + * Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type FindElementSimple = string; +export type FindElementDetailed = { + [k: string]: unknown; +}; +export type GoTo1 = GoToURLSimple | GoToURLDetailed; +/** + * Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any. + */ +export type GoToURLSimple = string; +/** + * Perform a generic HTTP request, for example to an API. + */ +export type HttpRequest1 = HTTPRequestSimple | HTTPRequestDetailed; +/** + * URL for the HTTP request. + */ +export type HTTPRequestSimple = string; +export type HTTPRequestDetailed = { + [k: string]: unknown; +}; +/** + * Perform a native shell command. + */ +export type RunShell1 = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; +/** + * Assemble and run code. + */ +export type RunCode1 = RunCodeDetailed; +/** + * Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`. + */ +export type TypeKeys = TypeKeysSimple | TypeKeysDetailed; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple = string | string[]; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple1 = string | string[]; +/** + * Takes a screenshot in PNG format. + */ +export type Screenshot1 = ScreenshotSimple | CaptureScreenshotDetailed | CaptureScreenshot; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple = string; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple1 = string; +/** + * Display text or selector of the element to screenshot. + */ +export type CropByElementSimple = string; +/** + * Crop the screenshot to a specific element. + */ +export type CropByElementDetailed = { + [k: string]: unknown; +}; +/** + * If `true`, captures a screenshot. If `false`, doesn't capture a screenshot. + */ +export type CaptureScreenshot = boolean; +/** + * Save a specific browser cookie to a file or environment variable for later reuse. + */ +export type SaveCookie1 = CookieName | SaveCookieDetailed; +/** + * Name of the specific cookie to save. Will be saved to a default file path or environment variable. + */ +export type CookieName = string; +export type SaveCookieDetailed = { + [k: string]: unknown; +}; +/** + * Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ] + */ +export type Record1 = RecordSimple | RecordDetailed | RecordBoolean; +/** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ +export type RecordSimple = string; +/** + * If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport. + */ +export type RecordBoolean = boolean; +/** + * Stop the current recording. + */ +export type StopRecord1 = boolean; +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables1 = string; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple = string; +export type ElementDetailed = { + [k: string]: unknown; +}; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple1 = string; +export type ElementDetailed1 = { + [k: string]: unknown; +}; +/** + * Load a specific cookie from a file or environment variable into the browser. + */ +export type LoadCookie1 = CookieNameOrFilePath | LoadCookieDetailed; +/** + * Name of the specific cookie to load from default location, or file path to cookie file. + */ +export type CookieNameOrFilePath = string; +export type LoadCookieDetailed = { + [k: string]: unknown; +}; +/** + * Pause (in milliseconds) before performing the next action. + */ +export type Wait1 = WaitSimple | WaitEnvironmentVariable | WaitBoolean; +export type WaitSimple = number; +export type WaitEnvironmentVariable = string; +export type WaitBoolean = boolean; + +export interface Common { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep; + variables?: VariablesStep; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface CheckLink { + checkLink: CheckLink1; + [k: string]: unknown; +} +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export interface CheckLinkDetailed1 { + /** + * URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. + */ + statusCodes?: number | number[]; +} +export interface Common1 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep1; + variables?: VariablesStep1; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep1 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep1`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep1 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep1`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Click { + click: Click1; + [k: string]: unknown; +} +export interface Common2 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep2; + variables?: VariablesStep2; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep2 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep2`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep2 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep2`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Find { + find: Find1; + [k: string]: unknown; +} +export interface Common3 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep3; + variables?: VariablesStep3; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep3 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep3`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep3 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep3`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface GoTo { + goTo: GoTo1; + [k: string]: unknown; +} +/** + * Navigate to an HTTP or HTTPS URL. + */ +export interface GoToURLDetailed { + /** + * URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails. + */ + timeout?: number; + /** + * Configuration for waiting conditions after navigation. + */ + waitUntil?: { + /** + * Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check. + */ + networkIdleTime?: number | null; + /** + * Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check. + */ + domIdleTime?: number | null; + /** + * Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified. + */ + find?: { + [k: string]: unknown; + }; + }; +} +export interface Common4 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep4; + variables?: VariablesStep4; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep4 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep4`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep4 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep4`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface HttpRequest { + httpRequest: HttpRequest1; + [k: string]: unknown; +} +export interface Common5 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep5; + variables?: VariablesStep5; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep5 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep5`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep5 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep5`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunShell { + runShell: RunShell1; + [k: string]: unknown; +} +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +export interface Common6 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep6; + variables?: VariablesStep6; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep6 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep6`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep6 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep6`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunCode { + runCode: RunCode1; + [k: string]: unknown; +} +export interface RunCodeDetailed { + /** + * Language of the code to run. + */ + language: "python" | "bash" | "javascript"; + /** + * Code to run. + */ + code: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; + [k: string]: unknown; +} +export interface Common7 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep7; + variables?: VariablesStep7; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep7 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep7`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep7 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep7`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Type { + type: TypeKeys; + [k: string]: unknown; +} +export interface TypeKeysDetailed { + keys: TypeKeysSimple1; + /** + * Delay in milliseconds between each key press during a recording + */ + inputDelay?: number; + /** + * Selector for the element to type into. If not specified, the typing occurs in the active element. + */ + selector?: string; + /** + * Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria. + */ + elementText?: string; + /** + * ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementId?: string; + /** + * data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementTestId?: string; + /** + * Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes. + */ + elementClass?: string | string[]; + /** + * Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence. + */ + elementAttribute?: { + [k: string]: string | number | boolean; + }; + /** + * Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementAria?: string; +} +export interface Common8 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep8; + variables?: VariablesStep8; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep8 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep8`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep8 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep8`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Screenshot { + screenshot: Screenshot1; + [k: string]: unknown; +} +export interface CaptureScreenshotDetailed { + path?: ScreenshotSimple1; + /** + * Directory of the PNG file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing screenshot at `path` if it exists. + * If `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + crop?: CropByElementSimple | CropByElementDetailed; + sourceIntegration?: SourceIntegration; +} +/** + * Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations. + */ +export interface SourceIntegration { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} +export interface Common9 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep9; + variables?: VariablesStep9; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep9 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep9`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep9 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep9`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface SaveCookie { + saveCookie: SaveCookie1; + [k: string]: unknown; +} +export interface Common10 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep10; + variables?: VariablesStep10; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep10 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep10`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep10 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep10`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Record { + record: Record1; + [k: string]: unknown; +} +export interface RecordDetailed { + /** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ + path?: string; + /** + * Directory of the file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * If `true`, overwrites the existing recording at `path` if it exists. + */ + overwrite?: "true" | "false"; + [k: string]: unknown; +} +export interface Common11 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep11; + variables?: VariablesStep11; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep11 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep11`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep11 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep11`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface StopRecord { + stopRecord: StopRecord1; + [k: string]: unknown; +} +export interface Common12 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep12; + variables?: VariablesStep12; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep12 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep12`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep12 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep12`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadVariables { + loadVariables: LoadVariables1; + [k: string]: unknown; +} +export interface Common13 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep13; + variables?: VariablesStep13; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep13 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep13`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep13 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep13`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface DragAndDrop { + dragAndDrop: DragAndDrop1; + [k: string]: unknown; +} +/** + * Drag and drop an element from source to target. + */ +export interface DragAndDrop1 { + /** + * The element to drag. + */ + source: ElementSimple | ElementDetailed; + /** + * The target location to drop the element. + */ + target: ElementSimple1 | ElementDetailed1; + /** + * Duration of the drag operation in milliseconds. + */ + duration?: number; + [k: string]: unknown; +} +export interface Common14 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep14; + variables?: VariablesStep14; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep14 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep14`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep14 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep14`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadCookie { + loadCookie: LoadCookie1; + [k: string]: unknown; +} +export interface Common15 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep15; + variables?: VariablesStep15; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep15 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep15`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep15 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep15`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Wait { + wait: Wait1; + [k: string]: unknown; +} diff --git a/src/types/generated/stopRecord_v3.ts b/src/types/generated/stopRecord_v3.ts new file mode 100644 index 00000000..bbc0051e --- /dev/null +++ b/src/types/generated/stopRecord_v3.ts @@ -0,0 +1,10 @@ +/* eslint-disable */ +/** + * Auto-generated from stopRecord_v3.schema.json + * Do not edit manually + */ + +/** + * Stop the current recording. + */ +export type StopRecord = boolean; diff --git a/src/types/generated/test_v3.ts b/src/types/generated/test_v3.ts new file mode 100644 index 00000000..45b40b91 --- /dev/null +++ b/src/types/generated/test_v3.ts @@ -0,0 +1,3048 @@ +/* eslint-disable */ +/** + * Auto-generated from test_v3.schema.json + * Do not edit manually + */ + +/** + * A Doc Detective test. + */ +export type Test = { + [k: string]: unknown; +} & { + /** + * Unique identifier for the test. + */ + testId?: string; + /** + * Description of the test. + */ + description?: string; + /** + * Path to the content that the test is associated with. + */ + contentPath?: string; + /** + * Whether or not to detect steps in input files based on markup regex. + */ + detectSteps?: boolean; + /** + * Contexts to run the test in. Overrides contexts defined at the config and spec levels. + */ + runOn?: Context[]; + openApi?: (OpenApi & OpenAPIDescriptionTest)[]; + /** + * Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec. + */ + before?: string; + /** + * Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec. + */ + after?: string; + /** + * Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed. + * + * @minItems 1 + */ + steps?: [Step, ...Step[]]; + contexts?: ResolvedContexts; +}; +/** + * OpenAPI description and configuration. + */ +export type OpenApi = { + [k: string]: unknown; +}; +/** + * A step in a test. + */ +export type Step = + | (Common & CheckLink) + | (Common1 & Click) + | (Common2 & Find) + | (Common3 & GoTo) + | (Common4 & HttpRequest) + | (Common5 & RunShell) + | (Common6 & RunCode) + | (Common7 & Type) + | (Common8 & Screenshot) + | (Common9 & SaveCookie) + | (Common10 & Record) + | (Common11 & StopRecord) + | (Common12 & LoadVariables) + | (Common13 & DragAndDrop) + | (Common14 & LoadCookie) + | (Common15 & Wait); +export type CheckLink1 = CheckLinkDetailed | CheckLinkDetailed1; +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export type CheckLinkDetailed = string; +/** + * Click or tap an element. + */ +export type Click1 = ClickElementSimple | ClickElementDetailed | boolean; +/** + * Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type ClickElementSimple = string; +export type ClickElementDetailed = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Find an element based on display text or a selector, then optionally interact with it. + */ +export type Find1 = FindElementSimple | FindElementDetailed; +/** + * Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type FindElementSimple = string; +export type FindElementDetailed = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +export type GoTo1 = GoToURLSimple | GoToURLDetailed; +/** + * Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any. + */ +export type GoToURLSimple = string; +/** + * Perform a generic HTTP request, for example to an API. + */ +export type HttpRequest1 = HTTPRequestSimple | HTTPRequestDetailed; +/** + * URL for the HTTP request. + */ +export type HTTPRequestSimple = string; +export type HTTPRequestDetailed = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Perform a native shell command. + */ +export type RunShell1 = RunShellCommandSimple | RunShellCommandDetailed; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple = string; +/** + * Assemble and run code. + */ +export type RunCode1 = RunCodeDetailed; +/** + * Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`. + */ +export type TypeKeys = TypeKeysSimple | TypeKeysDetailed; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple = string | string[]; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple1 = string | string[]; +/** + * Takes a screenshot in PNG format. + */ +export type Screenshot1 = ScreenshotSimple | CaptureScreenshotDetailed | CaptureScreenshot; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple = string; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple1 = string; +/** + * Display text or selector of the element to screenshot. + */ +export type CropByElementSimple = string; +/** + * Crop the screenshot to a specific element. + */ +export type CropByElementDetailed = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * If `true`, captures a screenshot. If `false`, doesn't capture a screenshot. + */ +export type CaptureScreenshot = boolean; +/** + * Save a specific browser cookie to a file or environment variable for later reuse. + */ +export type SaveCookie1 = CookieName | SaveCookieDetailed; +/** + * Name of the specific cookie to save. Will be saved to a default file path or environment variable. + */ +export type CookieName = string; +export type SaveCookieDetailed = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ] + */ +export type Record1 = RecordSimple | RecordDetailed | RecordBoolean; +/** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ +export type RecordSimple = string; +/** + * If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport. + */ +export type RecordBoolean = boolean; +/** + * Stop the current recording. + */ +export type StopRecord1 = boolean; +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables1 = string; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple = string; +export type ElementDetailed = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple1 = string; +export type ElementDetailed1 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Load a specific cookie from a file or environment variable into the browser. + */ +export type LoadCookie1 = CookieNameOrFilePath | LoadCookieDetailed; +/** + * Name of the specific cookie to load from default location, or file path to cookie file. + */ +export type CookieNameOrFilePath = string; +export type LoadCookieDetailed = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Pause (in milliseconds) before performing the next action. + */ +export type Wait1 = WaitSimple | WaitEnvironmentVariable | WaitBoolean; +export type WaitSimple = number; +export type WaitEnvironmentVariable = string; +export type WaitBoolean = boolean; +/** + * OpenAPI description and configuration. + */ +export type OpenApi1 = { + [k: string]: unknown; +}; +/** + * A step in a test. + */ +export type Step1 = + | (Common16 & CheckLink2) + | (Common17 & Click2) + | (Common18 & Find2) + | (Common19 & GoTo2) + | (Common20 & HttpRequest2) + | (Common21 & RunShell2) + | (Common22 & RunCode2) + | (Common23 & Type1) + | (Common24 & Screenshot2) + | (Common25 & SaveCookie2) + | (Common26 & Record2) + | (Common27 & StopRecord2) + | (Common28 & LoadVariables2) + | (Common29 & DragAndDrop2) + | (Common30 & LoadCookie2) + | (Common31 & Wait2); +export type CheckLink3 = CheckLinkDetailed2 | CheckLinkDetailed3; +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export type CheckLinkDetailed2 = string; +/** + * Click or tap an element. + */ +export type Click3 = ClickElementSimple1 | ClickElementDetailed1 | boolean; +/** + * Identifier for the element to click. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type ClickElementSimple1 = string; +export type ClickElementDetailed1 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Find an element based on display text or a selector, then optionally interact with it. + */ +export type Find3 = FindElementSimple1 | FindElementDetailed1; +/** + * Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID. + */ +export type FindElementSimple1 = string; +export type FindElementDetailed1 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +export type GoTo3 = GoToURLSimple1 | GoToURLDetailed1; +/** + * Navigate to an HTTP or HTTPS URL. Can be a full URL or a path. If a path is provided, navigates relative to the current URL, if any. + */ +export type GoToURLSimple1 = string; +/** + * Perform a generic HTTP request, for example to an API. + */ +export type HttpRequest3 = HTTPRequestSimple1 | HTTPRequestDetailed1; +/** + * URL for the HTTP request. + */ +export type HTTPRequestSimple1 = string; +export type HTTPRequestDetailed1 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Perform a native shell command. + */ +export type RunShell3 = RunShellCommandSimple1 | RunShellCommandDetailed1; +/** + * Command to perform in the machine's default shell. + */ +export type RunShellCommandSimple1 = string; +/** + * Assemble and run code. + */ +export type RunCode3 = RunCodeDetailed1; +/** + * Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`. + */ +export type TypeKeys1 = TypeKeysSimple2 | TypeKeysDetailed1; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple2 = string | string[]; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple3 = string | string[]; +/** + * Takes a screenshot in PNG format. + */ +export type Screenshot3 = ScreenshotSimple2 | CaptureScreenshotDetailed1 | CaptureScreenshot1; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple2 = string; +/** + * File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. + */ +export type ScreenshotSimple3 = string; +/** + * Display text or selector of the element to screenshot. + */ +export type CropByElementSimple1 = string; +/** + * Crop the screenshot to a specific element. + */ +export type CropByElementDetailed1 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * If `true`, captures a screenshot. If `false`, doesn't capture a screenshot. + */ +export type CaptureScreenshot1 = boolean; +/** + * Save a specific browser cookie to a file or environment variable for later reuse. + */ +export type SaveCookie3 = CookieName1 | SaveCookieDetailed1; +/** + * Name of the specific cookie to save. Will be saved to a default file path or environment variable. + */ +export type CookieName1 = string; +export type SaveCookieDetailed1 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Start recording the current browser viewport. Must be followed by a `stopRecord` step. Only runs in Chrome browsers when they are visible. Supported extensions: [ '.mp4', '.webm', '.gif' ] + */ +export type Record3 = RecordSimple1 | RecordDetailed1 | RecordBoolean1; +/** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ +export type RecordSimple1 = string; +/** + * If `true`, records the current browser viewport. If `false`, doesn't record the current browser viewport. + */ +export type RecordBoolean1 = boolean; +/** + * Stop the current recording. + */ +export type StopRecord3 = boolean; +/** + * Load environment variables from the specified `.env` file. + */ +export type LoadVariables3 = string; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple2 = string; +export type ElementDetailed2 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Display text, selector, or regex pattern (enclosed in forward slashes) of the element. + */ +export type ElementSimple3 = string; +export type ElementDetailed3 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Load a specific cookie from a file or environment variable into the browser. + */ +export type LoadCookie3 = CookieNameOrFilePath1 | LoadCookieDetailed1; +/** + * Name of the specific cookie to load from default location, or file path to cookie file. + */ +export type CookieNameOrFilePath1 = string; +export type LoadCookieDetailed1 = + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; +/** + * Pause (in milliseconds) before performing the next action. + */ +export type Wait3 = WaitSimple1 | WaitEnvironmentVariable1 | WaitBoolean1; +export type WaitSimple1 = number; +export type WaitEnvironmentVariable1 = string; +export type WaitBoolean1 = boolean; +/** + * Resolved contexts to run the test in. This is a resolved version of the `runOn` property. It is not user-defined and should not be used in test specifications. + */ +export type ResolvedContexts = ResolvedContext[]; + +/** + * A context in which to perform tests. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For example, if a browser isn't specified but is required by steps in the test, Doc Detective will search for and use a supported browser available in the current environment. + */ +export interface Context { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/context_v3.schema.json"; + /** + * Unique identifier for the context. + */ + contextId?: string; + /** + * Platforms to run tests on. + */ + platforms?: ("linux" | "mac" | "windows") | ("linux" | "mac" | "windows")[]; + /** + * Browsers to run tests on. + */ + browsers?: + | ("chrome" | "firefox" | "safari" | "webkit") + | Browser + | (("chrome" | "firefox" | "safari" | "webkit") | Browser1)[]; +} +/** + * Browser configuration. + */ +export interface Browser { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow; + viewport?: BrowserViewport; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +/** + * Browser configuration. + */ +export interface Browser1 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow1; + viewport?: BrowserViewport1; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow1 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport1 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest { + [k: string]: unknown; +} +export interface Common { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep; + variables?: VariablesStep; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface CheckLink { + checkLink: CheckLink1; + [k: string]: unknown; +} +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export interface CheckLinkDetailed1 { + /** + * URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. + */ + statusCodes?: number | number[]; +} +export interface Common1 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep1; + variables?: VariablesStep1; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep1 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep1`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep1 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep1`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Click { + click: Click1; + [k: string]: unknown; +} +export interface Common2 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep2; + variables?: VariablesStep2; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep2 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep2`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep2 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep2`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Find { + find: Find1; + [k: string]: unknown; +} +export interface Common3 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep3; + variables?: VariablesStep3; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep3 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep3`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep3 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep3`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface GoTo { + goTo: GoTo1; + [k: string]: unknown; +} +/** + * Navigate to an HTTP or HTTPS URL. + */ +export interface GoToURLDetailed { + /** + * URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails. + */ + timeout?: number; + /** + * Configuration for waiting conditions after navigation. + */ + waitUntil?: { + /** + * Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check. + */ + networkIdleTime?: number | null; + /** + * Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check. + */ + domIdleTime?: number | null; + /** + * Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified. + */ + find?: + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; + }; +} +export interface Common4 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep4; + variables?: VariablesStep4; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep4 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep4`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep4 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep4`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface HttpRequest { + httpRequest: HttpRequest1; + [k: string]: unknown; +} +export interface Common5 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep5; + variables?: VariablesStep5; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep5 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep5`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep5 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep5`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunShell { + runShell: RunShell1; + [k: string]: unknown; +} +export interface RunShellCommandDetailed { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +export interface Common6 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep6; + variables?: VariablesStep6; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep6 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep6`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep6 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep6`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunCode { + runCode: RunCode1; + [k: string]: unknown; +} +export interface RunCodeDetailed { + /** + * Language of the code to run. + */ + language: "python" | "bash" | "javascript"; + /** + * Code to run. + */ + code: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; + [k: string]: unknown; +} +export interface Common7 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep7; + variables?: VariablesStep7; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep7 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep7`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep7 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep7`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Type { + type: TypeKeys; + [k: string]: unknown; +} +export interface TypeKeysDetailed { + keys: TypeKeysSimple1; + /** + * Delay in milliseconds between each key press during a recording + */ + inputDelay?: number; + /** + * Selector for the element to type into. If not specified, the typing occurs in the active element. + */ + selector?: string; + /** + * Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria. + */ + elementText?: string; + /** + * ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementId?: string; + /** + * data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementTestId?: string; + /** + * Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes. + */ + elementClass?: string | string[]; + /** + * Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence. + */ + elementAttribute?: { + [k: string]: string | number | boolean; + }; + /** + * Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementAria?: string; +} +export interface Common8 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep8; + variables?: VariablesStep8; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep8 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep8`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep8 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep8`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Screenshot { + screenshot: Screenshot1; + [k: string]: unknown; +} +export interface CaptureScreenshotDetailed { + path?: ScreenshotSimple1; + /** + * Directory of the PNG file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing screenshot at `path` if it exists. + * If `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + crop?: CropByElementSimple | CropByElementDetailed; + sourceIntegration?: SourceIntegration; +} +/** + * Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations. + */ +export interface SourceIntegration { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} +export interface Common9 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep9; + variables?: VariablesStep9; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep9 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep9`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep9 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep9`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface SaveCookie { + saveCookie: SaveCookie1; + [k: string]: unknown; +} +export interface Common10 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep10; + variables?: VariablesStep10; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep10 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep10`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep10 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep10`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Record { + record: Record1; + [k: string]: unknown; +} +export interface RecordDetailed { + /** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ + path?: string; + /** + * Directory of the file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * If `true`, overwrites the existing recording at `path` if it exists. + */ + overwrite?: "true" | "false"; + [k: string]: unknown; +} +export interface Common11 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep11; + variables?: VariablesStep11; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep11 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep11`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep11 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep11`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface StopRecord { + stopRecord: StopRecord1; + [k: string]: unknown; +} +export interface Common12 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep12; + variables?: VariablesStep12; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep12 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep12`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep12 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep12`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadVariables { + loadVariables: LoadVariables1; + [k: string]: unknown; +} +export interface Common13 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep13; + variables?: VariablesStep13; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep13 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep13`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep13 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep13`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface DragAndDrop { + dragAndDrop: DragAndDrop1; + [k: string]: unknown; +} +/** + * Drag and drop an element from source to target. + */ +export interface DragAndDrop1 { + /** + * The element to drag. + */ + source: ElementSimple | ElementDetailed; + /** + * The target location to drop the element. + */ + target: ElementSimple1 | ElementDetailed1; + /** + * Duration of the drag operation in milliseconds. + */ + duration?: number; + [k: string]: unknown; +} +export interface Common14 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep14; + variables?: VariablesStep14; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep14 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep14`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep14 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep14`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadCookie { + loadCookie: LoadCookie1; + [k: string]: unknown; +} +export interface Common15 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep15; + variables?: VariablesStep15; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep15 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep15`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep15 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep15`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Wait { + wait: Wait1; + [k: string]: unknown; +} +export interface ResolvedContext { + /** + * Platform to run the test on. This is a resolved version of the `platforms` property. + */ + platform?: string; + browser?: Browser2; + openApi?: (OpenApi1 & OpenAPIDescriptionTest1)[]; + /** + * Steps to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. By default, if a step fails, the test stops and the remaining steps are not executed. + * + * @minItems 1 + */ + steps?: [Step1, ...Step1[]]; + [k: string]: unknown; +} +/** + * Browser configuration. + */ +export interface Browser2 { + /** + * Name of the browser. + */ + name: "chrome" | "firefox" | "safari" | "webkit"; + /** + * If `true`, runs the browser in headless mode. + */ + headless?: boolean; + window?: BrowserWindow2; + viewport?: BrowserViewport2; +} +/** + * Browser dimensions. + */ +export interface BrowserWindow2 { + /** + * Width of the browser window in pixels. + */ + width?: number; + /** + * Height of the browser window in pixels. + */ + height?: number; +} +/** + * Viewport dimensions. + */ +export interface BrowserViewport2 { + /** + * Width of the viewport in pixels. + */ + width?: number; + /** + * Height of the viewport in pixels. + */ + height?: number; +} +export interface OpenAPIDescriptionTest1 { + [k: string]: unknown; +} +export interface Common16 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep16; + variables?: VariablesStep16; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep16 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep16`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep16 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep16`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface CheckLink2 { + checkLink: CheckLink3; + [k: string]: unknown; +} +/** + * Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request. + */ +export interface CheckLinkDetailed3 { + /** + * URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. + */ + statusCodes?: number | number[]; +} +export interface Common17 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep17; + variables?: VariablesStep17; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep17 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep17`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep17 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep17`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Click2 { + click: Click3; + [k: string]: unknown; +} +export interface Common18 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep18; + variables?: VariablesStep18; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep18 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep18`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep18 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep18`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Find2 { + find: Find3; + [k: string]: unknown; +} +export interface Common19 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep19; + variables?: VariablesStep19; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep19 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep19`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep19 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep19`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface GoTo2 { + goTo: GoTo3; + [k: string]: unknown; +} +/** + * Navigate to an HTTP or HTTPS URL. + */ +export interface GoToURLDetailed1 { + /** + * URL to navigate to. Can be a full URL or a path. If a path is provided and `origin` is specified, prepends `origin` to `url`. If a path is provided but `origin` isn't specified, attempts to navigate relative to the current URL, if any. + */ + url: string; + /** + * Protocol and domain to navigate to. Prepended to `url`. + */ + origin?: string; + /** + * Maximum time in milliseconds to wait for the page to be ready. If exceeded, the goTo action fails. + */ + timeout?: number; + /** + * Configuration for waiting conditions after navigation. + */ + waitUntil?: { + /** + * Wait for network activity to be idle (no new requests) for this duration in milliseconds. Set to `null` to skip this check. + */ + networkIdleTime?: number | null; + /** + * Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check. + */ + domIdleTime?: number | null; + /** + * Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified. + */ + find?: + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + } + | { + [k: string]: unknown; + }; + }; +} +export interface Common20 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep20; + variables?: VariablesStep20; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep20 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep20`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep20 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep20`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface HttpRequest2 { + httpRequest: HttpRequest3; + [k: string]: unknown; +} +export interface Common21 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep21; + variables?: VariablesStep21; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep21 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep21`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep21 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep21`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunShell2 { + runShell: RunShell3; + [k: string]: unknown; +} +export interface RunShellCommandDetailed1 { + /** + * Command to perform in the machine's default shell. + */ + command: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's stdout or stderr. If the expected content can't be found in the command's stdout or stderr, the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; +} +export interface Common22 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep22; + variables?: VariablesStep22; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep22 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep22`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep22 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep22`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface RunCode2 { + runCode: RunCode3; + [k: string]: unknown; +} +export interface RunCodeDetailed1 { + /** + * Language of the code to run. + */ + language: "python" | "bash" | "javascript"; + /** + * Code to run. + */ + code: string; + /** + * Arguments for the command. + */ + args?: string[]; + /** + * Working directory for the command. + */ + workingDirectory?: string; + /** + * Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. + */ + exitCodes?: number[]; + /** + * Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.* /`. + */ + stdio?: string; + /** + * File path to save the command's output, relative to `directory`. + */ + path?: string; + /** + * Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. + */ + directory?: string; + /** + * Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing output at `path` if it exists. + * If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + /** + * Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. + */ + timeout?: number; + [k: string]: unknown; +} +export interface Common23 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep23; + variables?: VariablesStep23; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep23 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep23`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep23 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep23`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Type1 { + type: TypeKeys1; + [k: string]: unknown; +} +export interface TypeKeysDetailed1 { + keys: TypeKeysSimple3; + /** + * Delay in milliseconds between each key press during a recording + */ + inputDelay?: number; + /** + * Selector for the element to type into. If not specified, the typing occurs in the active element. + */ + selector?: string; + /** + * Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria. + */ + elementText?: string; + /** + * ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementId?: string; + /** + * data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementTestId?: string; + /** + * Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes. + */ + elementClass?: string | string[]; + /** + * Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence. + */ + elementAttribute?: { + [k: string]: string | number | boolean; + }; + /** + * Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementAria?: string; +} +export interface Common24 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep24; + variables?: VariablesStep24; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep24 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep24`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep24 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep24`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Screenshot2 { + screenshot: Screenshot3; + [k: string]: unknown; +} +export interface CaptureScreenshotDetailed1 { + path?: ScreenshotSimple3; + /** + * Directory of the PNG file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * Allowed variation in percentage of pixels between the new screenshot and the existing screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored. + */ + maxVariation?: number; + /** + * If `true`, overwrites the existing screenshot at `path` if it exists. + * If `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`. + */ + overwrite?: "true" | "false" | "aboveVariation"; + crop?: CropByElementSimple1 | CropByElementDetailed1; + sourceIntegration?: SourceIntegration1; +} +/** + * Information about the source integration for this screenshot, enabling upload of changed files back to the source CMS. Set automatically during test resolution for files from integrations. + */ +export interface SourceIntegration1 { + /** + * The type of integration. Currently supported: 'heretto'. Additional types may be added in the future. + */ + type: "heretto"; + /** + * The name of the integration configuration in the config file. Used to look up authentication credentials. + */ + integrationName: string; + /** + * The unique identifier (UUID) of the file in the source CMS. If not provided, the file will be looked up by path. + */ + fileId?: string; + /** + * The path of the file in the source CMS. Used for lookup if fileId is not available. + */ + filePath?: string; + /** + * The local path to the file that references this source. Used for resolving relative paths. + */ + contentPath?: string; +} +export interface Common25 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep25; + variables?: VariablesStep25; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep25 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep25`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep25 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep25`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface SaveCookie2 { + saveCookie: SaveCookie3; + [k: string]: unknown; +} +export interface Common26 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep26; + variables?: VariablesStep26; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep26 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep26`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep26 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep26`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Record2 { + record: Record3; + [k: string]: unknown; +} +export interface RecordDetailed1 { + /** + * File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`. + */ + path?: string; + /** + * Directory of the file. If the directory doesn't exist, creates the directory. + */ + directory?: string; + /** + * If `true`, overwrites the existing recording at `path` if it exists. + */ + overwrite?: "true" | "false"; + [k: string]: unknown; +} +export interface Common27 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep27; + variables?: VariablesStep27; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep27 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep27`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep27 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep27`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface StopRecord2 { + stopRecord: StopRecord3; + [k: string]: unknown; +} +export interface Common28 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep28; + variables?: VariablesStep28; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep28 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep28`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep28 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep28`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadVariables2 { + loadVariables: LoadVariables3; + [k: string]: unknown; +} +export interface Common29 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep29; + variables?: VariablesStep29; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep29 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep29`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep29 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep29`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface DragAndDrop2 { + dragAndDrop: DragAndDrop3; + [k: string]: unknown; +} +/** + * Drag and drop an element from source to target. + */ +export interface DragAndDrop3 { + /** + * The element to drag. + */ + source: ElementSimple2 | ElementDetailed2; + /** + * The target location to drop the element. + */ + target: ElementSimple3 | ElementDetailed3; + /** + * Duration of the drag operation in milliseconds. + */ + duration?: number; + [k: string]: unknown; +} +export interface Common30 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep30; + variables?: VariablesStep30; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep30 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep30`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep30 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep30`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface LoadCookie2 { + loadCookie: LoadCookie3; + [k: string]: unknown; +} +export interface Common31 { + /** + * JSON Schema for this object. + */ + $schema?: "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json"; + /** + * ID of the step. + */ + stepId?: string; + /** + * Description of the step. + */ + description?: string; + /** + * Whether or not the step may be unsafe. Unsafe steps may perform actions that could modify the system or environment in unexpected ways. Unsafe steps are only performed within Docker containers or if unsafe steps are enabled with the `allowUnsafeSteps` config property or the `--allow-unsafe` flag. + */ + unsafe?: boolean; + outputs?: OutputsStep31; + variables?: VariablesStep31; + /** + * Whether or not this step should act as a breakpoint when debugging is enabled. When `true`, execution will pause at this step when debug mode is enabled. + */ + breakpoint?: boolean; + [k: string]: unknown; +} +/** + * Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. + */ +export interface OutputsStep31 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `OutputsStep31`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +/** + * Environment variables to set from user-defined expressions. + */ +export interface VariablesStep31 { + /** + * Runtime expression for a user-defined output value. + * + * This interface was referenced by `VariablesStep31`'s JSON-Schema definition + * via the `patternProperty` "^[A-Za-z0-9_]+$". + */ + [k: string]: string; +} +export interface Wait2 { + wait: Wait3; + [k: string]: unknown; +} diff --git a/src/types/generated/type_v3.ts b/src/types/generated/type_v3.ts new file mode 100644 index 00000000..b90cc571 --- /dev/null +++ b/src/types/generated/type_v3.ts @@ -0,0 +1,56 @@ +/* eslint-disable */ +/** + * Auto-generated from type_v3.schema.json + * Do not edit manually + */ + +/** + * Type keys. To type special keys, begin and end the string with `$` and use the special key's keyword. For example, to type the Escape key, enter `$ESCAPE$`. + */ +export type TypeKeys = TypeKeysSimple | TypeKeysDetailed; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple = string | string[]; +/** + * Sequence of keys to enter. + */ +export type TypeKeysSimple1 = string | string[]; + +export interface TypeKeysDetailed { + keys: TypeKeysSimple1; + /** + * Delay in milliseconds between each key press during a recording + */ + inputDelay?: number; + /** + * Selector for the element to type into. If not specified, the typing occurs in the active element. + */ + selector?: string; + /** + * Display text of the element to type into. If combined with other element finding fields, the element must match all specified criteria. + */ + elementText?: string; + /** + * ID attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementId?: string; + /** + * data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementTestId?: string; + /** + * Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes. + */ + elementClass?: string | string[]; + /** + * Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence. + */ + elementAttribute?: { + [k: string]: string | number | boolean; + }; + /** + * Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax. + */ + elementAria?: string; +} diff --git a/src/types/generated/wait_v3.ts b/src/types/generated/wait_v3.ts new file mode 100644 index 00000000..36256d59 --- /dev/null +++ b/src/types/generated/wait_v3.ts @@ -0,0 +1,13 @@ +/* eslint-disable */ +/** + * Auto-generated from wait_v3.schema.json + * Do not edit manually + */ + +/** + * Pause (in milliseconds) before performing the next action. + */ +export type Wait = WaitSimple | WaitEnvironmentVariable | WaitBoolean; +export type WaitSimple = number; +export type WaitEnvironmentVariable = string; +export type WaitBoolean = boolean; diff --git a/src/validate.ts b/src/validate.ts new file mode 100644 index 00000000..6c9a7b7e --- /dev/null +++ b/src/validate.ts @@ -0,0 +1,605 @@ +import { schemas, SchemaKey } from "./schemas"; +import Ajv, { ValidateFunction } from "ajv"; +// Ajv extra formats: https://ajv.js.org/packages/ajv-formats.html +import addFormats from "ajv-formats"; +// Ajv extra keywords: https://ajv.js.org/packages/ajv-keywords.html +import addKeywords from "ajv-keywords"; +// Ajv custom errors: https://ajv.js.org/packages/ajv-errors.html +import addErrors from "ajv-errors"; +import { randomUUID } from "crypto"; + +// Configure base Ajv +const ajv = new Ajv({ + strictSchema: false, + useDefaults: true, + allErrors: true, + allowUnionTypes: true, + coerceTypes: true, +}); + +// Enable `uuid` dynamic default +// @ts-ignore - ajv-keywords has incomplete types for dynamicDefaults +const def = require("ajv-keywords/dist/definitions/dynamicDefaults"); +def.DEFAULTS.uuid = () => randomUUID; + +// Enhance Ajv +addFormats(ajv); +addKeywords(ajv); +addErrors(ajv); + +// Add all schemas from `schema` object. +for (const [key, value] of Object.entries(schemas)) { + ajv.addSchema(value, key); +} + +type CompatibleSchemaKey = keyof typeof compatibleSchemas; + +const compatibleSchemas: Partial> = { + config_v3: ["config_v2"], + context_v3: ["context_v2"], + openApi_v3: ["openApi_v2"], + spec_v3: ["spec_v2"], + step_v3: [ + "checkLink_v2", + "find_v2", + "goTo_v2", + "httpRequest_v2", + "runShell_v2", + "runCode_v2", + "saveScreenshot_v2", + "setVariables_v2", + "startRecording_v2", + "stopRecording_v2", + "typeKeys_v2", + "wait_v2", + ], + test_v3: ["test_v2"], +}; + +export interface ValidateOptions { + schemaKey: string; + object: any; + addDefaults?: boolean; +} + +export interface ValidateResult { + valid: boolean; + errors: string; + object: any; +} + +export interface TransformOptions { + currentSchema: string; + targetSchema: string; + object: any; +} + +/** + * Escapes special characters in a string for safe use in a regular expression pattern. + * + * @param string - The input string to escape. + * @returns The escaped string, safe for use in regular expressions. + */ +function escapeRegExp(string: string): string { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string +} + +/** + * Validates an object against a specified JSON schema, supporting backward compatibility and automatic transformation from older schema versions if needed. + * + * If validation against the target schema fails and compatible older schemas are defined, attempts validation against each compatible schema. On a match, transforms the object to the target schema and revalidates. Returns the validation result, any errors, and the (possibly transformed) object. + * + * @param options - Validation options + * @param options.schemaKey - The key identifying the target JSON schema. + * @param options.object - The object to validate. + * @param options.addDefaults - Whether to include default values in the returned object. + * @returns Validation result, error messages, and the validated (and possibly transformed) object. + * + * @throws {Error} If {@link schemaKey} or {@link object} is missing. + */ +export function validate({ schemaKey, object, addDefaults = true }: ValidateOptions): ValidateResult { + if (!schemaKey) { + throw new Error("Schema key is required."); + } + if (!object) { + throw new Error("Object is required."); + } + const result: ValidateResult = { + valid: false, + errors: "", + object: object, + }; + let validationObject: any; + let check: ValidateFunction | undefined = ajv.getSchema(schemaKey); + if (!check) { + result.valid = false; + result.errors = `Schema not found: ${schemaKey}`; + result.object = object; + return result; + } + + // Clone the object to avoid modifying the original object + validationObject = JSON.parse(JSON.stringify(object)); + + // Check if the object is compatible with the schema + result.valid = check(validationObject); + result.errors = ""; + + if (check.errors) { + // Check if the object is compatible with another schema + const compatibleSchemasList = compatibleSchemas[schemaKey as keyof typeof compatibleSchemas]; + if (!compatibleSchemasList) { + result.errors = check.errors + .map( + (error) => + `${error.instancePath} ${error.message} (${JSON.stringify( + error.params + )})` + ) + .join(", "); + result.object = object; + result.valid = false; + return result; + } + const matchedSchemaKey = compatibleSchemasList.find((key) => { + validationObject = JSON.parse(JSON.stringify(object)); + const check = ajv.getSchema(key); + if (check && check(validationObject)) return key; + }); + if (!matchedSchemaKey) { + result.errors = check.errors + .map( + (error) => + `${error.instancePath} ${error.message} (${JSON.stringify( + error.params + )})` + ) + .join(", "); + result.object = object; + result.valid = false; + return result; + } else { + const transformedObject = transformToSchemaKey({ + currentSchema: matchedSchemaKey, + targetSchema: schemaKey, + object: validationObject, + }); + + result.valid = check(transformedObject); + if (result.valid) { + validationObject = transformedObject; + object = transformedObject; + /* c8 ignore start - Defensive: transformToSchemaKey validates internally, so this is unreachable */ + } else if (check.errors) { + const errors = check.errors.map( + (error) => + `${error.instancePath} ${error.message} (${JSON.stringify( + error.params + )})` + ); + result.errors = errors.join(", "); + return result; + } + /* c8 ignore stop */ + } + } + if (addDefaults) { + result.object = validationObject; + } else { + result.object = object; + } + + return result; +} + +/** + * Transform an object from one schema key to another and return a validated instance of the target schema. + * + * @param params - Function parameters. + * @param params.currentSchema - Schema key representing the object's current version. + * @param params.targetSchema - Schema key to transform the object into. + * @param params.object - The source object to transform. + * @returns The transformed object conforming to the target schema. + * @throws {Error} If transformation between the specified schemas is not supported or if the transformed object fails validation. + */ +export function transformToSchemaKey({ + currentSchema = "", + targetSchema = "", + object = {}, +}: TransformOptions): any { + // Check if the current schema is the same as the target schema + if (currentSchema === targetSchema) { + return object; + } + // Check if the current schema is compatible with the target schema + if (!compatibleSchemas[targetSchema as keyof typeof compatibleSchemas]?.includes(currentSchema as any)) { + throw new Error( + `Can't transform from ${currentSchema} to ${targetSchema}.` + ); + } + // Transform the object + if (targetSchema === "step_v3") { + const transformedObject: any = { + stepId: object.id, + description: object.description, + }; + if (currentSchema === "goTo_v2") { + transformedObject.goTo = { + url: object.url, + origin: object.origin, + }; + } else if (currentSchema === "checkLink_v2") { + transformedObject.checkLink = { + url: object.url, + origin: object.origin, + statusCodes: object.statusCodes, + }; + } else if (currentSchema === "find_v2") { + transformedObject.find = { + selector: object.selector, + elementText: object.matchText, + timeout: object.timeout, + moveTo: object.moveTo, + click: object.click, + type: object.typeKeys, + }; + // Handle typeKeys.delay key change + if (typeof object.typeKeys === "object" && object.typeKeys.keys) { + transformedObject.find.type.inputDelay = object.typeKeys.delay; + delete transformedObject.find.type.delay; + } + transformedObject.variables = {}; + object.setVariables?.forEach((variable: any) => { + transformedObject.variables[ + variable.name + ] = `extract($$element.text, "${variable.regex}")`; + }); + } else if (currentSchema === "httpRequest_v2") { + transformedObject.httpRequest = { + method: object.method, + url: object.url, + openApi: object.openApi, + request: { + body: object.requestData, + headers: object.requestHeaders, + parameters: object.requestParams, + }, + response: { + body: object.responseData, + headers: object.responseHeaders, + }, + statusCodes: object.statusCodes, + allowAdditionalFields: object.allowAdditionalFields, + timeout: object.timeout, + path: object.savePath, + directory: object.saveDirectory, + maxVariation: object.maxVariation / 100, + overwrite: + object.overwrite === "byVariation" + ? "aboveVariation" + : object.overwrite, + }; + // Handle openApi.requestHeaders key change + if (object.openApi) { + transformedObject.httpRequest.openApi = transformToSchemaKey({ + currentSchema: "openApi_v2", + targetSchema: "openApi_v3", + object: object.openApi, + }); + } + transformedObject.variables = {}; + object.envsFromResponseData?.forEach((variable: any) => { + transformedObject.variables[ + variable.name + ] = `jq($$response.body, "${variable.jqFilter}")`; + }); + } else if (currentSchema === "runShell_v2") { + transformedObject.runShell = { + command: object.command, + args: object.args, + workingDirectory: object.workingDirectory, + exitCodes: object.exitCodes, + stdio: object.output, + path: object.savePath, + directory: object.saveDirectory, + maxVariation: object.maxVariation / 100, + overwrite: + object.overwrite === "byVariation" + ? "aboveVariation" + : object.overwrite, + timeout: object.timeout, + }; + transformedObject.variables = {}; + object.setVariables?.forEach((variable: any) => { + transformedObject.variables[ + variable.name + ] = `extract($$stdio.stdout, "${variable.regex}")`; + }); + } else if (currentSchema === "runCode_v2") { + transformedObject.runCode = { + language: object.language, + code: object.code, + args: object.args, + workingDirectory: object.workingDirectory, + exitCodes: object.exitCodes, + stdio: object.output, + path: object.savePath, + directory: object.saveDirectory, + maxVariation: object.maxVariation / 100, + overwrite: + object.overwrite === "byVariation" + ? "aboveVariation" + : object.overwrite, + timeout: object.timeout, + }; + transformedObject.variables = {}; + object?.setVariables?.forEach((variable: any) => { + transformedObject.variables[ + variable.name + ] = `extract($$stdio.stdout, "${variable.regex}")`; + }); + } else if (currentSchema === "setVariables_v2") { + transformedObject.loadVariables = object.path; + } else if (currentSchema === "typeKeys_v2") { + transformedObject.type = { + keys: object.keys, + inputDelay: object.delay, + }; + } else if (currentSchema === "saveScreenshot_v2") { + transformedObject.screenshot = { + path: object.path, + directory: object.directory, + maxVariation: object.maxVariation / 100, + overwrite: + object.overwrite === "byVariation" + ? "aboveVariation" + : object.overwrite, + crop: object.crop, + }; + } else if (currentSchema === "startRecording_v2") { + transformedObject.record = { + path: object.path, + directory: object.directory, + overwrite: object.overwrite, + }; + } else if (currentSchema === "stopRecording_v2") { + transformedObject.stopRecord = true; + } else if (currentSchema === "wait_v2") { + transformedObject.wait = object; + } + const result = validate({ + schemaKey: "step_v3", + object: transformedObject, + }); + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } else if (targetSchema === "config_v3") { + // Handle config_v2 to config_v3 transformation + const transformedObject: any = { + loadVariables: object.envVariables, + input: object?.runTests?.input || object.input, + output: object?.runTests?.output || object.output, + recursive: object?.runTests?.recursive || object.recursive, + relativePathBase: object.relativePathBase, + detectSteps: object?.runTests?.detectSteps, + beforeAny: object?.runTests?.setup, + afterAll: object?.runTests?.cleanup, + logLevel: object.logLevel, + telemetry: object.telemetry, + }; + // Handle context transformation + if (object?.runTests?.contexts) + transformedObject.runOn = object.runTests.contexts.map((context: any) => + transformToSchemaKey({ + currentSchema: "context_v2", + targetSchema: "context_v3", + object: context, + }) + ); + // Handle openApi transformation + if (object?.integrations?.openApi) { + transformedObject.integrations = {}; + transformedObject.integrations.openApi = object.integrations.openApi.map( + (description: any) => + transformToSchemaKey({ + currentSchema: "openApi_v2", + targetSchema: "openApi_v3", + object: description, + }) + ); + } + // Handle fileTypes transformation + if (object?.fileTypes) + transformedObject.fileTypes = object.fileTypes.map((fileType: any) => { + const transformedFileType: any = { + name: fileType.name, + extensions: fileType.extensions.map((extension: string) => + // Trim leading `.` from extension + extension.replace(/^\./, "") + ), + inlineStatements: { + // Convert strings to regex, escaping special characters + testStart: `${escapeRegExp( + fileType.testStartStatementOpen + )}(.*?)${escapeRegExp(fileType.testStartStatementClose)}`, + testEnd: escapeRegExp(fileType.testEndStatement), + ignoreStart: escapeRegExp(fileType.testIgnoreStatement), + step: `${escapeRegExp( + fileType.stepStatementOpen + )}(.*?)${escapeRegExp(fileType.stepStatementClose)}`, + }, + }; + if (fileType.markup) + transformedFileType.markup = fileType.markup.map((markup: any) => { + const transformedMarkup: any = { + name: markup.name, + regex: markup.regex, + }; + if (markup.actions) + transformedMarkup.actions = markup.actions.map((action: any) => { + if (typeof action === "string") return action; + if (typeof action === "object") { + if (action.params) { + action = { + action: action.name, + ...action.params, + }; + } + const transformedAction = transformToSchemaKey({ + currentSchema: `${action.action}_v2`, + targetSchema: "step_v3", + object: action, + }); + return transformedAction; + } + }); + + return transformedMarkup; + }); + return transformedFileType; + }); + const result = validate({ + schemaKey: "config_v3", + object: transformedObject, + }); + // Defensive: transformation always produces valid config_v3, unreachable + /* c8 ignore next 3 */ + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } else if (targetSchema === "context_v3") { + const transformedObject: any = {}; + // Handle context_v2 to context_v3 transformation + transformedObject.platforms = object.platforms; + if (object.app?.name) { + const name = object.app.name === "edge" ? "chrome" : object.app?.name; + transformedObject.browsers = []; + transformedObject.browsers.push({ + name, + headless: object.app?.options?.headless, + window: { + width: object.app?.options?.width, + height: object.app?.options?.height, + }, + viewport: { + width: object.app?.options?.viewport_width, + height: object.app?.options?.viewport_height, + }, + }); + } + const result = validate({ + schemaKey: "context_v3", + object: transformedObject, + }); + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } else if (targetSchema === "openApi_v3") { + let transformedObject: any; + // Handle openApi_v2 to openApi_v3 transformation + const { name, requestHeaders, ...intermediaryObject } = object; + intermediaryObject.name = object.name; + intermediaryObject.headers = object.requestHeaders; + transformedObject = { ...intermediaryObject }; + + const result = validate({ + schemaKey: "openApi_v3", + object: transformedObject, + }); + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return transformedObject; + } else if (targetSchema === "spec_v3") { + // Handle spec_v2 to spec_v3 transformation + const transformedObject: any = { + specId: object.id, + description: object.description, + contentPath: object.file, + }; + if (object.contexts) + transformedObject.runOn = object.contexts.map((context: any) => + transformToSchemaKey({ + currentSchema: "context_v2", + targetSchema: "context_v3", + object: context, + }) + ); + if (object.openApi) + transformedObject.openApi = object.openApi.map((description: any) => + transformToSchemaKey({ + currentSchema: "openApi_v2", + targetSchema: "openApi_v3", + object: description, + }) + ); + transformedObject.tests = object.tests.map((test: any) => + transformToSchemaKey({ + currentSchema: "test_v2", + targetSchema: "test_v3", + object: test, + }) + ); + + const result = validate({ + schemaKey: "spec_v3", + object: transformedObject, + }); + // Defensive: nested transforms validate; this is unreachable + /* c8 ignore next 3 */ + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } else if (targetSchema === "test_v3") { + // Handle test_v2 to test_v3 transformation + const transformedObject: any = { + testId: object.id, + description: object.description, + contentPath: object.file, + detectSteps: object.detectSteps, + before: object.setup, + after: object.cleanup, + }; + if (object.contexts) + transformedObject.runOn = object.contexts.map((context: any) => + transformToSchemaKey({ + currentSchema: "context_v2", + targetSchema: "context_v3", + object: context, + }) + ); + if (object.openApi) + transformedObject.openApi = object.openApi.map((description: any) => + transformToSchemaKey({ + currentSchema: "openApi_v2", + targetSchema: "openApi_v3", + object: description, + }) + ); + transformedObject.steps = object.steps.map((step: any) => + transformToSchemaKey({ + currentSchema: `${step.action}_v2`, + targetSchema: "step_v3", + object: step, + }) + ); + + const result = validate({ + schemaKey: "test_v3", + object: transformedObject, + }); + // Defensive: nested transforms validate; this is unreachable + /* c8 ignore next 3 */ + if (!result.valid) { + throw new Error(`Invalid object: ${result.errors}`); + } + return result.object; + } + /* c8 ignore next - Dead code: incompatible schemas throw at line 197-200 */ + return null; +} diff --git a/test/files.test.js b/test/files.test.js index 6d899ee1..9a72ca5b 100644 --- a/test/files.test.js +++ b/test/files.test.js @@ -1,7 +1,7 @@ const sinon = require("sinon"); const axios = require("axios"); const fs = require("fs"); -const { readFile } = require("../src/files"); +const { readFile } = require("../dist/files"); (async () => { const { expect } = await import("chai"); diff --git a/test/resolvePaths.test.js b/test/resolvePaths.test.js index 24f1ae7e..be6c24b6 100644 --- a/test/resolvePaths.test.js +++ b/test/resolvePaths.test.js @@ -4,7 +4,7 @@ const path = require("path"); (async () => { const { expect } = await import("chai"); - const { resolvePaths } = require("../src/resolvePaths"); + const { resolvePaths } = require("../dist/resolvePaths"); describe("resolvePaths", function () { const mockFilePath = "/home/user/project/config.json"; diff --git a/test/schema.test.js b/test/schema.test.js index f3acc711..f4411bd6 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -1,4 +1,4 @@ -const { validate, schemas } = require("../src/index"); +const { validate, schemas } = require("../dist/index"); const assert = require("assert"); // Loop through JSON schemas diff --git a/test/validate.test.js b/test/validate.test.js index 26dc68e8..8ecdc1f3 100644 --- a/test/validate.test.js +++ b/test/validate.test.js @@ -1,6 +1,6 @@ (async () => { const { expect } = await import("chai"); - const { validate, transformToSchemaKey } = require("../src/validate"); + const { validate, transformToSchemaKey } = require("../dist/validate"); describe("validate", function () { describe("input validation", function () { diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..dda928f9 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16", + "lib": ["ES2022"], + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "types": ["node"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test", "src/schemas/dereferenceSchemas.js"] +} From c792035658ca8b51e3cb431ac7dbb5fe327d18dd Mon Sep 17 00:00:00 2001 From: Joseph McCarron Date: Sat, 17 Jan 2026 06:09:26 +0000 Subject: [PATCH 2/4] typescript documentation --- README.md | 32 +- docs/typescript-examples.md | 580 +++++++++++++++++++++++++++++++++++ docs/typescript-migration.md | 580 +++++++++++++++++++++++++++++++++++ 3 files changed, 1191 insertions(+), 1 deletion(-) create mode 100644 docs/typescript-examples.md create mode 100644 docs/typescript-migration.md diff --git a/README.md b/README.md index f2dac152..d0c4752d 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,36 @@ This package exports the following components: - `readFile` - File reading utilities - `transformToSchemaKey` - Schema key transformation +### TypeScript Support + +Full TypeScript support with exported types: + +```typescript +import { + validate, + ValidateOptions, + ValidateResult, + resolvePaths, + ResolvePathsOptions +} from 'doc-detective-common'; +``` + +**Documentation:** +- [TypeScript Migration Guide](./docs/typescript-migration.md) - Complete guide for TypeScript users +- [TypeScript Examples](./docs/typescript-examples.md) - Runnable code examples + +### JavaScript Usage + +Works seamlessly with JavaScript (CommonJS or ESM): + +```javascript +// CommonJS +const { validate, schemas } = require('doc-detective-common'); + +// ESM +import { validate, schemas } from 'doc-detective-common'; +``` + ## 🧪 Development ```bash @@ -45,4 +75,4 @@ npm run build ## 📄 License -AGPL-3.0-only \ No newline at end of file +AGPL-3.0-only diff --git a/docs/typescript-examples.md b/docs/typescript-examples.md new file mode 100644 index 00000000..1813f6aa --- /dev/null +++ b/docs/typescript-examples.md @@ -0,0 +1,580 @@ +# TypeScript Examples + +Complete, runnable examples showing how to use `doc-detective-common` with TypeScript. + +## Setup + +```bash +npm install doc-detective-common +npm install --save-dev typescript @types/node +``` + +**tsconfig.json:** +```json +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + } +} +``` + +## Example 1: Config Validator + +Create a type-safe config validator with helpful error messages. + +```typescript +import { validate, readFile, ValidateResult } from 'doc-detective-common'; +import * as path from 'path'; + +interface ConfigValidatorOptions { + configPath: string; + allowDefaults?: boolean; +} + +interface ConfigValidatorResult { + success: boolean; + config?: any; + errors?: string[]; +} + +async function validateConfig( + options: ConfigValidatorOptions +): Promise { + const { configPath, allowDefaults = true } = options; + + // Read config file + const content = await readFile({ fileURLOrPath: configPath }); + + if (content === null) { + return { + success: false, + errors: [`Config file not found: ${configPath}`] + }; + } + + if (typeof content === 'string') { + return { + success: false, + errors: ['Config file could not be parsed'] + }; + } + + // Validate against schema + const result: ValidateResult = validate({ + schemaKey: 'config_v3', + object: content, + addDefaults: allowDefaults + }); + + if (!result.valid) { + return { + success: false, + errors: result.errors.split(', ') + }; + } + + return { + success: true, + config: result.object + }; +} + +// Usage +async function main() { + const result = await validateConfig({ + configPath: './doc-detective.config.json', + allowDefaults: true + }); + + if (result.success) { + console.log('✓ Config is valid:', result.config); + } else { + console.error('✗ Config errors:'); + result.errors?.forEach(err => console.error(` - ${err}`)); + process.exit(1); + } +} + +main().catch(console.error); +``` + +## Example 2: Spec File Processor + +Load, validate, and resolve paths in spec files. + +```typescript +import { + validate, + readFile, + resolvePaths, + ValidateResult, + ResolvePathsOptions +} from 'doc-detective-common'; +import * as path from 'path'; +import * as fs from 'fs/promises'; + +interface SpecProcessor { + load(specPath: string): Promise; + validate(spec: any): ValidateResult; + resolvePaths(spec: any, basePath: string): Promise; + process(specPath: string): Promise; +} + +class SpecFileProcessor implements SpecProcessor { + async load(specPath: string): Promise { + const content = await readFile({ fileURLOrPath: specPath }); + + if (content === null) { + throw new Error(`Spec file not found: ${specPath}`); + } + + if (typeof content === 'string') { + throw new Error('Spec file is not valid JSON/YAML'); + } + + return content; + } + + validate(spec: any): ValidateResult { + return validate({ + schemaKey: 'spec_v3', + object: spec, + addDefaults: true + }); + } + + async resolvePaths(spec: any, basePath: string): Promise { + const options: ResolvePathsOptions = { + config: { relativePathBase: 'file' }, + object: spec, + filePath: basePath + }; + + return await resolvePaths(options); + } + + async process(specPath: string): Promise { + // Load + const spec = await this.load(specPath); + + // Validate + const validation = this.validate(spec); + if (!validation.valid) { + throw new Error(`Invalid spec: ${validation.errors}`); + } + + // Resolve paths + const resolved = await this.resolvePaths( + validation.object, + path.dirname(specPath) + ); + + return resolved; + } +} + +// Usage +async function main() { + const processor = new SpecFileProcessor(); + + try { + const spec = await processor.process('./specs/getting-started.json'); + console.log('✓ Spec processed successfully'); + console.log('Tests:', spec.tests?.length ?? 0); + } catch (error) { + if (error instanceof Error) { + console.error('✗ Error:', error.message); + } + process.exit(1); + } +} + +main().catch(console.error); +``` + +## Example 3: Schema Version Migrator + +Automatically upgrade old schema versions to the latest. + +```typescript +import { + validate, + transformToSchemaKey, + ValidateResult, + TransformOptions +} from 'doc-detective-common'; + +type SchemaVersion = 'v2' | 'v3'; + +interface MigrationResult { + migrated: boolean; + fromVersion?: SchemaVersion; + toVersion: SchemaVersion; + object: any; + errors?: string; +} + +class SchemaMigrator { + private readonly targetVersion: SchemaVersion = 'v3'; + + migrateConfig(config: any): MigrationResult { + return this.migrate('config', config); + } + + migrateSpec(spec: any): MigrationResult { + return this.migrate('spec', spec); + } + + migrateTest(test: any): MigrationResult { + return this.migrate('test', test); + } + + private migrate(type: string, object: any): MigrationResult { + const targetSchema = `${type}_v3`; + + // Check if already v3 + const v3Check: ValidateResult = validate({ + schemaKey: targetSchema, + object + }); + + if (v3Check.valid) { + return { + migrated: false, + toVersion: 'v3', + object: v3Check.object + }; + } + + // Try migrating from v2 + try { + const options: TransformOptions = { + currentSchema: `${type}_v2`, + targetSchema, + object + }; + + const migrated = transformToSchemaKey(options); + + return { + migrated: true, + fromVersion: 'v2', + toVersion: 'v3', + object: migrated + }; + } catch (error) { + const errorMsg = error instanceof Error ? error.message : 'Unknown error'; + return { + migrated: false, + toVersion: 'v3', + object, + errors: `Migration failed: ${errorMsg}` + }; + } + } +} + +// Usage +async function main() { + const migrator = new SchemaMigrator(); + + const oldConfig = { + envVariables: './vars.json', + runTests: { + input: './specs', + output: './output' + } + }; + + const result = migrator.migrateConfig(oldConfig); + + if (result.errors) { + console.error('✗ Migration failed:', result.errors); + process.exit(1); + } + + if (result.migrated) { + console.log(`✓ Migrated from ${result.fromVersion} to ${result.toVersion}`); + } else { + console.log('✓ Already latest version'); + } + + console.log('Config:', result.object); +} + +main().catch(console.error); +``` + +## Example 4: Step Validator with Custom Types + +Define your own types for specific step types and validate them. + +```typescript +import { validate, ValidateResult } from 'doc-detective-common'; + +// Define your expected step structures +interface GoToStep { + stepId?: string; + description?: string; + goTo: { + url: string; + origin?: string; + }; +} + +interface FindStep { + stepId?: string; + description?: string; + find: { + selector: string; + elementText?: string; + timeout?: number; + }; +} + +type Step = GoToStep | FindStep; + +class StepValidator { + validate(step: unknown): ValidateResult { + return validate({ + schemaKey: 'step_v3', + object: step, + addDefaults: true + }); + } + + isGoToStep(step: any): step is GoToStep { + return step.goTo !== undefined; + } + + isFindStep(step: any): step is FindStep { + return step.find !== undefined; + } + + validateAndType(step: unknown): Step { + const result = this.validate(step); + + if (!result.valid) { + throw new Error(`Invalid step: ${result.errors}`); + } + + const validated = result.object; + + if (this.isGoToStep(validated)) { + return validated as GoToStep; + } + + if (this.isFindStep(validated)) { + return validated as FindStep; + } + + throw new Error('Unknown step type'); + } +} + +// Usage +function main() { + const validator = new StepValidator(); + + const steps = [ + { goTo: { url: 'https://example.com' } }, + { find: { selector: '#login-button' } } + ]; + + for (const step of steps) { + try { + const validated = validator.validateAndType(step); + + if (validator.isGoToStep(validated)) { + console.log('Navigate to:', validated.goTo.url); + } else if (validator.isFindStep(validated)) { + console.log('Find element:', validated.find.selector); + } + } catch (error) { + if (error instanceof Error) { + console.error('Error:', error.message); + } + } + } +} + +main(); +``` + +## Example 5: Batch File Processor + +Process multiple spec files with progress reporting. + +```typescript +import { + validate, + readFile, + resolvePaths, + ValidateResult +} from 'doc-detective-common'; +import * as fs from 'fs/promises'; +import * as path from 'path'; + +interface ProcessingResult { + file: string; + success: boolean; + error?: string; +} + +interface BatchProcessorOptions { + inputDir: string; + outputDir: string; + recursive?: boolean; +} + +class BatchSpecProcessor { + private results: ProcessingResult[] = []; + + async process(options: BatchProcessorOptions): Promise { + const { inputDir, outputDir, recursive = false } = options; + + // Find all spec files + const files = await this.findSpecFiles(inputDir, recursive); + console.log(`Found ${files.length} spec files`); + + // Process each file + for (const file of files) { + await this.processFile(file, inputDir, outputDir); + } + + return this.results; + } + + private async findSpecFiles( + dir: string, + recursive: boolean + ): Promise { + const entries = await fs.readdir(dir, { withFileTypes: true }); + const files: string[] = []; + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + + if (entry.isDirectory() && recursive) { + const subFiles = await this.findSpecFiles(fullPath, recursive); + files.push(...subFiles); + } else if (entry.isFile() && entry.name.endsWith('.json')) { + files.push(fullPath); + } + } + + return files; + } + + private async processFile( + filePath: string, + inputDir: string, + outputDir: string + ): Promise { + try { + // Load file + const content = await readFile({ fileURLOrPath: filePath }); + + if (content === null || typeof content === 'string') { + throw new Error('Could not parse spec file'); + } + + // Validate + const result: ValidateResult = validate({ + schemaKey: 'spec_v3', + object: content, + addDefaults: true + }); + + if (!result.valid) { + throw new Error(result.errors); + } + + // Resolve paths + const resolved = await resolvePaths({ + config: { relativePathBase: 'file' }, + object: result.object, + filePath + }); + + // Save to output directory + const relativePath = path.relative(inputDir, filePath); + const outputPath = path.join(outputDir, relativePath); + await fs.mkdir(path.dirname(outputPath), { recursive: true }); + await fs.writeFile(outputPath, JSON.stringify(resolved, null, 2)); + + this.results.push({ + file: relativePath, + success: true + }); + + console.log(`✓ ${relativePath}`); + } catch (error) { + const errorMsg = error instanceof Error ? error.message : 'Unknown error'; + this.results.push({ + file: path.relative(inputDir, filePath), + success: false, + error: errorMsg + }); + + console.error(`✗ ${path.relative(inputDir, filePath)}: ${errorMsg}`); + } + } + + printSummary(): void { + const successful = this.results.filter(r => r.success).length; + const failed = this.results.filter(r => !r.success).length; + + console.log('\n--- Summary ---'); + console.log(`Total: ${this.results.length}`); + console.log(`Success: ${successful}`); + console.log(`Failed: ${failed}`); + + if (failed > 0) { + console.log('\nFailed files:'); + this.results + .filter(r => !r.success) + .forEach(r => console.log(` - ${r.file}: ${r.error}`)); + } + } +} + +// Usage +async function main() { + const processor = new BatchSpecProcessor(); + + const results = await processor.process({ + inputDir: './specs', + outputDir: './processed', + recursive: true + }); + + processor.printSummary(); + + const failed = results.filter(r => !r.success).length; + process.exit(failed > 0 ? 1 : 0); +} + +main().catch(console.error); +``` + +## Running the Examples + +1. Save any example to a `.ts` file (e.g., `config-validator.ts`) +2. Compile: `npx tsc config-validator.ts` +3. Run: `node config-validator.js` + +Or use `ts-node` for direct execution: +```bash +npm install --save-dev ts-node +npx ts-node config-validator.ts +``` + +## More Examples + +See the [test files](../test/) for more usage patterns and edge cases. diff --git a/docs/typescript-migration.md b/docs/typescript-migration.md new file mode 100644 index 00000000..fdd226e6 --- /dev/null +++ b/docs/typescript-migration.md @@ -0,0 +1,580 @@ +# TypeScript Migration Guide + +This guide helps downstream consumers migrate to the TypeScript version of `doc-detective-common` and leverage the new type definitions. + +## Table of Contents + +- [Breaking Changes](#breaking-changes) +- [Installation](#installation) +- [Basic Usage](#basic-usage) +- [Available Types](#available-types) +- [Common Patterns](#common-patterns) +- [Generated Schema Types](#generated-schema-types) +- [Migration Examples](#migration-examples) + +## Breaking Changes + +**None!** The TypeScript migration is 100% backward compatible. Existing JavaScript code continues to work without modifications. + +## Installation + +No changes needed. The package works the same way: + +```bash +npm install doc-detective-common +``` + +## Basic Usage + +### JavaScript (Unchanged) + +```javascript +const { validate, schemas, resolvePaths, readFile } = require('doc-detective-common'); + +// Use as before +const result = validate({ + schemaKey: 'step_v3', + object: { goTo: { url: 'https://example.com' } } +}); +``` + +### TypeScript (New) + +```typescript +import { + validate, + schemas, + resolvePaths, + readFile, + ValidateOptions, + ValidateResult, + ResolvePathsOptions, + ReadFileOptions +} from 'doc-detective-common'; + +// Now with full type safety +const options: ValidateOptions = { + schemaKey: 'step_v3', + object: { goTo: { url: 'https://example.com' } } +}; + +const result: ValidateResult = validate(options); +if (result.valid) { + console.log('Valid!', result.object); +} else { + console.error('Invalid:', result.errors); +} +``` + +### ESM Support (New) + +```javascript +import { validate, schemas } from 'doc-detective-common'; + +// Works in ESM modules now +``` + +## Available Types + +### Core Function Types + +#### `validate()` + +```typescript +import { ValidateOptions, ValidateResult } from 'doc-detective-common'; + +interface ValidateOptions { + schemaKey: string; + object: any; + addDefaults?: boolean; +} + +interface ValidateResult { + valid: boolean; + errors: string; + object: any; +} +``` + +**Example:** +```typescript +import { validate, ValidateOptions, ValidateResult } from 'doc-detective-common'; + +const options: ValidateOptions = { + schemaKey: 'config_v3', + object: { + input: './specs', + output: './output' + }, + addDefaults: true +}; + +const result: ValidateResult = validate(options); +``` + +#### `transformToSchemaKey()` + +```typescript +import { TransformOptions } from 'doc-detective-common'; + +interface TransformOptions { + currentSchema: string; + targetSchema: string; + object: any; +} +``` + +**Example:** +```typescript +import { transformToSchemaKey, TransformOptions } from 'doc-detective-common'; + +const options: TransformOptions = { + currentSchema: 'config_v2', + targetSchema: 'config_v3', + object: { /* v2 config */ } +}; + +const upgraded = transformToSchemaKey(options); +``` + +#### `resolvePaths()` + +```typescript +import { ResolvePathsOptions } from 'doc-detective-common'; + +interface ResolvePathsOptions { + config: { relativePathBase: 'file' | 'cwd' }; + object: Record; + filePath: string; + nested?: boolean; + objectType?: 'config' | 'spec'; +} +``` + +**Example:** +```typescript +import { resolvePaths, ResolvePathsOptions } from 'doc-detective-common'; + +const options: ResolvePathsOptions = { + config: { relativePathBase: 'file' }, + object: { + tests: [{ + steps: [{ + screenshot: { path: './screenshot.png' } + }] + }] + }, + filePath: '/path/to/spec.json' +}; + +const resolved = await resolvePaths(options); +``` + +#### `readFile()` + +```typescript +import { ReadFileOptions } from 'doc-detective-common'; + +interface ReadFileOptions { + fileURLOrPath: string; +} +``` + +**Example:** +```typescript +import { readFile, ReadFileOptions } from 'doc-detective-common'; + +const options: ReadFileOptions = { + fileURLOrPath: './config.yaml' +}; + +const content: unknown | string | null = await readFile(options); + +// Type narrowing +if (content !== null) { + if (typeof content === 'string') { + console.log('Raw content:', content); + } else { + console.log('Parsed object:', content); + } +} +``` + +### Schema Types + +```typescript +import { SchemaKey, Schema } from 'doc-detective-common'; + +type SchemaKey = + | 'step_v3' + | 'config_v3' + | 'spec_v3' + | 'test_v3' + | 'context_v3' + | 'checkLink_v3' + | 'click_v3' + // ... and 40+ more schema keys + +type Schema = any; // JSON Schema definition +``` + +**Example:** +```typescript +import { schemas, SchemaKey } from 'doc-detective-common'; + +function validateAgainstSchema(key: SchemaKey, data: any) { + const schema = schemas[key]; + // schema is properly typed +} +``` + +## Common Patterns + +### Pattern 1: Validating User Input + +```typescript +import { validate, ValidateResult } from 'doc-detective-common'; + +function validateStep(stepData: unknown): ValidateResult { + return validate({ + schemaKey: 'step_v3', + object: stepData, + addDefaults: true + }); +} + +// Usage +const result = validateStep({ goTo: { url: 'https://example.com' } }); +if (!result.valid) { + throw new Error(`Invalid step: ${result.errors}`); +} +``` + +### Pattern 2: Type-Safe Config Loading + +```typescript +import { readFile, validate } from 'doc-detective-common'; + +async function loadConfig(path: string) { + const content = await readFile({ fileURLOrPath: path }); + + if (content === null) { + throw new Error(`Failed to read config from ${path}`); + } + + const result = validate({ + schemaKey: 'config_v3', + object: content, + addDefaults: true + }); + + if (!result.valid) { + throw new Error(`Invalid config: ${result.errors}`); + } + + return result.object; +} +``` + +### Pattern 3: Path Resolution with Type Safety + +```typescript +import { resolvePaths, ResolvePathsOptions } from 'doc-detective-common'; + +async function processSpec(spec: any, specPath: string) { + const options: ResolvePathsOptions = { + config: { relativePathBase: 'file' }, + object: spec, + filePath: specPath + }; + + return await resolvePaths(options); +} +``` + +### Pattern 4: Schema Version Upgrade + +```typescript +import { transformToSchemaKey, validate } from 'doc-detective-common'; + +function upgradeConfig(oldConfig: any) { + // First check if it's already v3 + const v3Check = validate({ + schemaKey: 'config_v3', + object: oldConfig + }); + + if (v3Check.valid) { + return oldConfig; + } + + // Try to upgrade from v2 + try { + return transformToSchemaKey({ + currentSchema: 'config_v2', + targetSchema: 'config_v3', + object: oldConfig + }); + } catch (error) { + throw new Error('Config is neither v2 nor v3 format'); + } +} +``` + +## Generated Schema Types + +The package auto-generates TypeScript interfaces for all v3 schemas. These are available in the compiled output: + +```typescript +// Note: These types are in dist/types/generated/ but not exported from main package +// They're primarily for internal use. Use validation at runtime instead. +``` + +### Why Not Export Schema Types? + +The generated types from JSON schemas are extensive (26 files with many nested types) and have naming collisions. Instead, we recommend: + +1. **Runtime validation** with `validate()` - More flexible and handles schema evolution +2. **Type assertions** when you know the shape: + +```typescript +import { validate } from 'doc-detective-common'; + +interface MyStep { + stepId?: string; + description?: string; + goTo?: { + url: string; + origin?: string; + }; +} + +function processStep(step: MyStep) { + // Validate at runtime + const result = validate({ + schemaKey: 'step_v3', + object: step + }); + + if (!result.valid) { + throw new Error(result.errors); + } + + // Now you can work with validated data + return result.object as MyStep; +} +``` + +## Migration Examples + +### Example 1: Simple JavaScript to TypeScript + +**Before (JavaScript):** +```javascript +const { validate } = require('doc-detective-common'); + +function checkStep(step) { + const result = validate({ + schemaKey: 'step_v3', + object: step + }); + return result.valid; +} +``` + +**After (TypeScript):** +```typescript +import { validate, ValidateOptions, ValidateResult } from 'doc-detective-common'; + +function checkStep(step: unknown): boolean { + const options: ValidateOptions = { + schemaKey: 'step_v3', + object: step + }; + + const result: ValidateResult = validate(options); + return result.valid; +} +``` + +### Example 2: File Reading with Type Guards + +**Before (JavaScript):** +```javascript +const { readFile } = require('doc-detective-common'); + +async function loadSpec(path) { + const content = await readFile({ fileURLOrPath: path }); + if (content) { + return content; + } + throw new Error('Failed to load'); +} +``` + +**After (TypeScript):** +```typescript +import { readFile, ReadFileOptions } from 'doc-detective-common'; + +async function loadSpec(path: string): Promise { + const options: ReadFileOptions = { fileURLOrPath: path }; + const content = await readFile(options); + + if (content === null) { + throw new Error('Failed to load'); + } + + return content; +} +``` + +### Example 3: Schema Transformation with Error Handling + +**Before (JavaScript):** +```javascript +const { transformToSchemaKey } = require('doc-detective-common'); + +function upgrade(config) { + try { + return transformToSchemaKey({ + currentSchema: 'config_v2', + targetSchema: 'config_v3', + object: config + }); + } catch (err) { + console.error(err.message); + return null; + } +} +``` + +**After (TypeScript):** +```typescript +import { transformToSchemaKey, TransformOptions } from 'doc-detective-common'; + +function upgrade(config: unknown): unknown | null { + const options: TransformOptions = { + currentSchema: 'config_v2', + targetSchema: 'config_v3', + object: config + }; + + try { + return transformToSchemaKey(options); + } catch (err) { + if (err instanceof Error) { + console.error(err.message); + } + return null; + } +} +``` + +## Best Practices + +### 1. Always Validate User Input + +```typescript +import { validate } from 'doc-detective-common'; + +function processUserConfig(userInput: unknown) { + const result = validate({ + schemaKey: 'config_v3', + object: userInput, + addDefaults: true + }); + + if (!result.valid) { + throw new Error(`Invalid config: ${result.errors}`); + } + + // Now safe to use + return result.object; +} +``` + +### 2. Use Type Narrowing for File Content + +```typescript +import { readFile } from 'doc-detective-common'; + +async function loadYaml(path: string) { + const content = await readFile({ fileURLOrPath: path }); + + // Type narrowing + if (content === null) { + throw new Error('File not found'); + } + + if (typeof content === 'string') { + throw new Error('Failed to parse YAML'); + } + + // Now content is 'unknown' (parsed object) + return content; +} +``` + +### 3. Combine Validation with Type Assertions + +```typescript +import { validate } from 'doc-detective-common'; + +interface ExpectedConfig { + input: string; + output: string; +} + +function loadConfig(data: unknown): ExpectedConfig { + const result = validate({ + schemaKey: 'config_v3', + object: data + }); + + if (!result.valid) { + throw new Error(result.errors); + } + + // Safe to assert after validation + return result.object as ExpectedConfig; +} +``` + +### 4. Handle Async Operations Properly + +```typescript +import { resolvePaths, readFile } from 'doc-detective-common'; + +async function processSpecFile(path: string) { + // Load file + const content = await readFile({ fileURLOrPath: path }); + + if (content === null || typeof content === 'string') { + throw new Error('Invalid spec file'); + } + + // Resolve paths + const resolved = await resolvePaths({ + config: { relativePathBase: 'file' }, + object: content, + filePath: path + }); + + return resolved; +} +``` + +## Need Help? + +- **Issues**: Report bugs or request features at https://github.com/doc-detective/doc-detective-common/issues +- **Discussions**: Ask questions at https://github.com/doc-detective/doc-detective-common/discussions +- **Documentation**: See main [README.md](../README.md) for general usage + +## Version Compatibility + +| Version | TypeScript Support | Module Systems | +|---------|-------------------|----------------| +| < 4.0 | No (JavaScript only) | CommonJS | +| >= 4.0 | Yes (Full types) | CommonJS + ESM | + +Your existing code continues to work without changes! From d3d6083a626871db4469de634f9e94699e2185b3 Mon Sep 17 00:00:00 2001 From: Joseph McCarron Date: Sat, 17 Jan 2026 06:19:07 +0000 Subject: [PATCH 3/4] resolve errors in validate.ts by casting --- dist/validate.d.ts | 2 +- dist/validate.d.ts.map | 2 +- dist/validate.js | 19 ++++++---- dist/validate.js.map | 2 +- src/validate.ts | 80 +++++++++++++++++++++++------------------- 5 files changed, 59 insertions(+), 46 deletions(-) diff --git a/dist/validate.d.ts b/dist/validate.d.ts index f95cd88b..7b1654cc 100644 --- a/dist/validate.d.ts +++ b/dist/validate.d.ts @@ -26,7 +26,7 @@ export interface TransformOptions { * * @throws {Error} If {@link schemaKey} or {@link object} is missing. */ -export declare function validate({ schemaKey, object, addDefaults }: ValidateOptions): ValidateResult; +export declare function validate({ schemaKey, object, addDefaults, }: ValidateOptions): ValidateResult; /** * Transform an object from one schema key to another and return a validated instance of the target schema. * diff --git a/dist/validate.d.ts.map b/dist/validate.d.ts.map index 713de211..22771565 100644 --- a/dist/validate.d.ts.map +++ b/dist/validate.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AA0DA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,GAAG,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,GAAG,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,GAAG,CAAC;CACb;AAYD;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,WAAkB,EAAE,EAAE,eAAe,GAAG,cAAc,CA6FnG;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,aAAkB,EAClB,YAAiB,EACjB,MAAW,GACZ,EAAE,gBAAgB,GAAG,GAAG,CA4YxB"} \ No newline at end of file +{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AA2DA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,GAAG,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,GAAG,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,GAAG,CAAC;CACb;AAYD;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,MAAM,EACN,WAAkB,GACnB,EAAE,eAAe,GAAG,cAAc,CA8FlC;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,aAAkB,EAClB,YAAiB,EACjB,MAAW,GACZ,EAAE,gBAAgB,GAAG,GAAG,CA4YxB"} \ No newline at end of file diff --git a/dist/validate.js b/dist/validate.js index 908dde84..773d647c 100644 --- a/dist/validate.js +++ b/dist/validate.js @@ -34,6 +34,7 @@ def.DEFAULTS.uuid = () => crypto_1.randomUUID; for (const [key, value] of Object.entries(schemas_1.schemas)) { ajv.addSchema(value, key); } +// Define the specific schemas that have compatibility mappings const compatibleSchemas = { config_v3: ["config_v2"], context_v3: ["context_v2"], @@ -77,7 +78,7 @@ function escapeRegExp(string) { * * @throws {Error} If {@link schemaKey} or {@link object} is missing. */ -function validate({ schemaKey, object, addDefaults = true }) { +function validate({ schemaKey, object, addDefaults = true, }) { if (!schemaKey) { throw new Error("Schema key is required."); } @@ -171,7 +172,9 @@ function transformToSchemaKey({ currentSchema = "", targetSchema = "", object = return object; } // Check if the current schema is compatible with the target schema - if (!compatibleSchemas[targetSchema]?.includes(currentSchema)) { + const compatibleList = compatibleSchemas[targetSchema]; + if (!compatibleList || + !compatibleList.includes(currentSchema)) { throw new Error(`Can't transform from ${currentSchema} to ${targetSchema}.`); } // Transform the object @@ -209,7 +212,8 @@ function transformToSchemaKey({ currentSchema = "", targetSchema = "", object = } transformedObject.variables = {}; object.setVariables?.forEach((variable) => { - transformedObject.variables[variable.name] = `extract($$element.text, "${variable.regex}")`; + transformedObject.variables[variable.name] = + `extract($$element.text, "${variable.regex}")`; }); } else if (currentSchema === "httpRequest_v2") { @@ -246,7 +250,8 @@ function transformToSchemaKey({ currentSchema = "", targetSchema = "", object = } transformedObject.variables = {}; object.envsFromResponseData?.forEach((variable) => { - transformedObject.variables[variable.name] = `jq($$response.body, "${variable.jqFilter}")`; + transformedObject.variables[variable.name] = + `jq($$response.body, "${variable.jqFilter}")`; }); } else if (currentSchema === "runShell_v2") { @@ -266,7 +271,8 @@ function transformToSchemaKey({ currentSchema = "", targetSchema = "", object = }; transformedObject.variables = {}; object.setVariables?.forEach((variable) => { - transformedObject.variables[variable.name] = `extract($$stdio.stdout, "${variable.regex}")`; + transformedObject.variables[variable.name] = + `extract($$stdio.stdout, "${variable.regex}")`; }); } else if (currentSchema === "runCode_v2") { @@ -287,7 +293,8 @@ function transformToSchemaKey({ currentSchema = "", targetSchema = "", object = }; transformedObject.variables = {}; object?.setVariables?.forEach((variable) => { - transformedObject.variables[variable.name] = `extract($$stdio.stdout, "${variable.regex}")`; + transformedObject.variables[variable.name] = + `extract($$stdio.stdout, "${variable.regex}")`; }); } else if (currentSchema === "setVariables_v2") { diff --git a/dist/validate.js.map b/dist/validate.js.map index a912309d..12897d2e 100644 --- a/dist/validate.js.map +++ b/dist/validate.js.map @@ -1 +1 @@ -{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":";;;;;AAmGA,4BA6FC;AAYD,oDAgZC;AA5lBD,uCAA+C;AAC/C,8CAA4C;AAC5C,kEAAkE;AAClE,8DAAqC;AACrC,oEAAoE;AACpE,gEAAuC;AACvC,iEAAiE;AACjE,4DAAmC;AACnC,mCAAoC;AAEpC,qBAAqB;AACrB,MAAM,GAAG,GAAG,IAAI,aAAG,CAAC;IAClB,YAAY,EAAE,KAAK;IACnB,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,IAAI;IACf,eAAe,EAAE,IAAI;IACrB,WAAW,EAAE,IAAI;CAClB,CAAC,CAAC;AAEH,gCAAgC;AAChC,qEAAqE;AACrE,MAAM,GAAG,GAAG,OAAO,CAAC,+CAA+C,CAAC,CAAC;AACrE,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC,mBAAU,CAAC;AAErC,cAAc;AACd,IAAA,qBAAU,EAAC,GAAG,CAAC,CAAC;AAChB,IAAA,sBAAW,EAAC,GAAG,CAAC,CAAC;AACjB,IAAA,oBAAS,EAAC,GAAG,CAAC,CAAC;AAEf,wCAAwC;AACxC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,iBAAO,CAAC,EAAE,CAAC;IACnD,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC;AAID,MAAM,iBAAiB,GAA4C;IACjE,SAAS,EAAE,CAAC,WAAW,CAAC;IACxB,UAAU,EAAE,CAAC,YAAY,CAAC;IAC1B,UAAU,EAAE,CAAC,YAAY,CAAC;IAC1B,OAAO,EAAE,CAAC,SAAS,CAAC;IACpB,OAAO,EAAE;QACP,cAAc;QACd,SAAS;QACT,SAAS;QACT,gBAAgB;QAChB,aAAa;QACb,YAAY;QACZ,mBAAmB;QACnB,iBAAiB;QACjB,mBAAmB;QACnB,kBAAkB;QAClB,aAAa;QACb,SAAS;KACV;IACD,OAAO,EAAE,CAAC,SAAS,CAAC;CACrB,CAAC;AAoBF;;;;;GAKG;AACH,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC,oCAAoC;AAC5F,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,EAAmB;IACjF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,MAAM,GAAmB;QAC7B,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,MAAM;KACf,CAAC;IACF,IAAI,gBAAqB,CAAC;IAC1B,IAAI,KAAK,GAAiC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACnE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,MAAM,CAAC,MAAM,GAAG,qBAAqB,SAAS,EAAE,CAAC;QACjD,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,0DAA0D;IAC1D,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAEtD,oDAAoD;IACpD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACvC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;IAEnB,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,wDAAwD;QACxD,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,SAA2C,CAAC,CAAC;QAC7F,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC3B,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;iBACzB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CACR,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,SAAS,CACvD,KAAK,CAAC,MAAM,CACb,GAAG,CACP;iBACA,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;YACrB,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YAC1D,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;YACtD,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,KAAK,IAAI,KAAK,CAAC,gBAAgB,CAAC;gBAAE,OAAO,GAAG,CAAC;QACnD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;iBACzB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CACR,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,SAAS,CACvD,KAAK,CAAC,MAAM,CACb,GAAG,CACP;iBACA,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;YACrB,OAAO,MAAM,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,MAAM,iBAAiB,GAAG,oBAAoB,CAAC;gBAC7C,aAAa,EAAE,gBAAgB;gBAC/B,YAAY,EAAE,SAAS;gBACvB,MAAM,EAAE,gBAAgB;aACzB,CAAC,CAAC;YAEH,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACxC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,gBAAgB,GAAG,iBAAiB,CAAC;gBACrC,MAAM,GAAG,iBAAiB,CAAC;gBAC3B,oGAAoG;YACtG,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAC7B,CAAC,KAAK,EAAE,EAAE,CACR,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,SAAS,CACvD,KAAK,CAAC,MAAM,CACb,GAAG,CACP,CAAC;gBACF,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClC,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,oBAAoB;QACtB,CAAC;IACH,CAAC;IACD,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,MAAM,GAAG,gBAAgB,CAAC;IACnC,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,oBAAoB,CAAC,EACnC,aAAa,GAAG,EAAE,EAClB,YAAY,GAAG,EAAE,EACjB,MAAM,GAAG,EAAE,GACM;IACjB,+DAA+D;IAC/D,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;QACnC,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,mEAAmE;IACnE,IAAI,CAAC,iBAAiB,CAAC,YAA8C,CAAC,EAAE,QAAQ,CAAC,aAAoB,CAAC,EAAE,CAAC;QACvG,MAAM,IAAI,KAAK,CACb,wBAAwB,aAAa,OAAO,YAAY,GAAG,CAC5D,CAAC;IACJ,CAAC;IACD,uBAAuB;IACvB,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,iBAAiB,GAAQ;YAC7B,MAAM,EAAE,MAAM,CAAC,EAAE;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;SAChC,CAAC;QACF,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,iBAAiB,CAAC,IAAI,GAAG;gBACvB,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,cAAc,EAAE,CAAC;YAC5C,iBAAiB,CAAC,SAAS,GAAG;gBAC5B,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,WAAW,EAAE,MAAM,CAAC,WAAW;aAChC,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YACvC,iBAAiB,CAAC,IAAI,GAAG;gBACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,WAAW,EAAE,MAAM,CAAC,SAAS;gBAC7B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,IAAI,EAAE,MAAM,CAAC,QAAQ;aACtB,CAAC;YACF,mCAAmC;YACnC,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAChE,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAC/D,OAAO,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;YAC3C,CAAC;YACD,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAC;YACjC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE;gBAC7C,iBAAiB,CAAC,SAAS,CACzB,QAAQ,CAAC,IAAI,CACd,GAAG,4BAA4B,QAAQ,CAAC,KAAK,IAAI,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,aAAa,KAAK,gBAAgB,EAAE,CAAC;YAC9C,iBAAiB,CAAC,WAAW,GAAG;gBAC9B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM,CAAC,WAAW;oBACxB,OAAO,EAAE,MAAM,CAAC,cAAc;oBAC9B,UAAU,EAAE,MAAM,CAAC,aAAa;iBACjC;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,MAAM,CAAC,YAAY;oBACzB,OAAO,EAAE,MAAM,CAAC,eAAe;iBAChC;gBACD,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;gBACnD,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,SAAS,EAAE,MAAM,CAAC,aAAa;gBAC/B,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,GAAG;gBACvC,SAAS,EACP,MAAM,CAAC,SAAS,KAAK,aAAa;oBAChC,CAAC,CAAC,gBAAgB;oBAClB,CAAC,CAAC,MAAM,CAAC,SAAS;aACvB,CAAC;YACF,2CAA2C;YAC3C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,iBAAiB,CAAC,WAAW,CAAC,OAAO,GAAG,oBAAoB,CAAC;oBAC3D,aAAa,EAAE,YAAY;oBAC3B,YAAY,EAAE,YAAY;oBAC1B,MAAM,EAAE,MAAM,CAAC,OAAO;iBACvB,CAAC,CAAC;YACL,CAAC;YACD,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAC;YACjC,MAAM,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE;gBACrD,iBAAiB,CAAC,SAAS,CACzB,QAAQ,CAAC,IAAI,CACd,GAAG,wBAAwB,QAAQ,CAAC,QAAQ,IAAI,CAAC;YACpD,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,aAAa,KAAK,aAAa,EAAE,CAAC;YAC3C,iBAAiB,CAAC,QAAQ,GAAG;gBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;gBACzC,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,MAAM;gBACpB,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,SAAS,EAAE,MAAM,CAAC,aAAa;gBAC/B,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,GAAG;gBACvC,SAAS,EACP,MAAM,CAAC,SAAS,KAAK,aAAa;oBAChC,CAAC,CAAC,gBAAgB;oBAClB,CAAC,CAAC,MAAM,CAAC,SAAS;gBACtB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC;YACF,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAC;YACjC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE;gBAC7C,iBAAiB,CAAC,SAAS,CACzB,QAAQ,CAAC,IAAI,CACd,GAAG,4BAA4B,QAAQ,CAAC,KAAK,IAAI,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;YAC1C,iBAAiB,CAAC,OAAO,GAAG;gBAC1B,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;gBACzC,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,MAAM;gBACpB,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,SAAS,EAAE,MAAM,CAAC,aAAa;gBAC/B,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,GAAG;gBACvC,SAAS,EACP,MAAM,CAAC,SAAS,KAAK,aAAa;oBAChC,CAAC,CAAC,gBAAgB;oBAClB,CAAC,CAAC,MAAM,CAAC,SAAS;gBACtB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC;YACF,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAC;YACjC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE;gBAC9C,iBAAiB,CAAC,SAAS,CACzB,QAAQ,CAAC,IAAI,CACd,GAAG,4BAA4B,QAAQ,CAAC,KAAK,IAAI,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,aAAa,KAAK,iBAAiB,EAAE,CAAC;YAC/C,iBAAiB,CAAC,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC;QAChD,CAAC;aAAM,IAAI,aAAa,KAAK,aAAa,EAAE,CAAC;YAC3C,iBAAiB,CAAC,IAAI,GAAG;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,UAAU,EAAE,MAAM,CAAC,KAAK;aACzB,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,mBAAmB,EAAE,CAAC;YACjD,iBAAiB,CAAC,UAAU,GAAG;gBAC7B,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,GAAG;gBACvC,SAAS,EACP,MAAM,CAAC,SAAS,KAAK,aAAa;oBAChC,CAAC,CAAC,gBAAgB;oBAClB,CAAC,CAAC,MAAM,CAAC,SAAS;gBACtB,IAAI,EAAE,MAAM,CAAC,IAAI;aAClB,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,mBAAmB,EAAE,CAAC;YACjD,iBAAiB,CAAC,MAAM,GAAG;gBACzB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;aAC5B,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,kBAAkB,EAAE,CAAC;YAChD,iBAAiB,CAAC,UAAU,GAAG,IAAI,CAAC;QACtC,CAAC;aAAM,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YACvC,iBAAiB,CAAC,IAAI,GAAG,MAAM,CAAC;QAClC,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,SAAS;YACpB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;SAAM,IAAI,YAAY,KAAK,WAAW,EAAE,CAAC;QACxC,+CAA+C;QAC/C,MAAM,iBAAiB,GAAQ;YAC7B,aAAa,EAAE,MAAM,CAAC,YAAY;YAClC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI,MAAM,CAAC,KAAK;YAC9C,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,MAAM,CAAC,MAAM;YACjD,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,IAAI,MAAM,CAAC,SAAS;YAC1D,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;YACzC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW;YAC1C,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK;YAClC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO;YACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,SAAS,EAAE,MAAM,CAAC,SAAS;SAC5B,CAAC;QACF,gCAAgC;QAChC,IAAI,MAAM,EAAE,QAAQ,EAAE,QAAQ;YAC5B,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAY,EAAE,EAAE,CACtE,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,OAAO;aAChB,CAAC,CACH,CAAC;QACJ,gCAAgC;QAChC,IAAI,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;YAClC,iBAAiB,CAAC,YAAY,GAAG,EAAE,CAAC;YACpC,iBAAiB,CAAC,YAAY,CAAC,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CACtE,CAAC,WAAgB,EAAE,EAAE,CACnB,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,WAAW;aACpB,CAAC,CACL,CAAC;QACJ,CAAC;QACD,kCAAkC;QAClC,IAAI,MAAM,EAAE,SAAS;YACnB,iBAAiB,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAa,EAAE,EAAE;gBACnE,MAAM,mBAAmB,GAAQ;oBAC/B,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAiB,EAAE,EAAE;oBACxD,kCAAkC;oBAClC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAC7B;oBACD,gBAAgB,EAAE;wBAChB,wDAAwD;wBACxD,SAAS,EAAE,GAAG,YAAY,CACxB,QAAQ,CAAC,sBAAsB,CAChC,QAAQ,YAAY,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE;wBACzD,OAAO,EAAE,YAAY,CAAC,QAAQ,CAAC,gBAAgB,CAAC;wBAChD,WAAW,EAAE,YAAY,CAAC,QAAQ,CAAC,mBAAmB,CAAC;wBACvD,IAAI,EAAE,GAAG,YAAY,CACnB,QAAQ,CAAC,iBAAiB,CAC3B,QAAQ,YAAY,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE;qBACrD;iBACF,CAAC;gBACF,IAAI,QAAQ,CAAC,MAAM;oBACjB,mBAAmB,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAW,EAAE,EAAE;wBAC/D,MAAM,iBAAiB,GAAQ;4BAC7B,IAAI,EAAE,MAAM,CAAC,IAAI;4BACjB,KAAK,EAAE,MAAM,CAAC,KAAK;yBACpB,CAAC;wBACF,IAAI,MAAM,CAAC,OAAO;4BAChB,iBAAiB,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAW,EAAE,EAAE;gCAC7D,IAAI,OAAO,MAAM,KAAK,QAAQ;oCAAE,OAAO,MAAM,CAAC;gCAC9C,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;oCAC/B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;wCAClB,MAAM,GAAG;4CACP,MAAM,EAAE,MAAM,CAAC,IAAI;4CACnB,GAAG,MAAM,CAAC,MAAM;yCACjB,CAAC;oCACJ,CAAC;oCACD,MAAM,iBAAiB,GAAG,oBAAoB,CAAC;wCAC7C,aAAa,EAAE,GAAG,MAAM,CAAC,MAAM,KAAK;wCACpC,YAAY,EAAE,SAAS;wCACvB,MAAM,EAAE,MAAM;qCACf,CAAC,CAAC;oCACH,OAAO,iBAAiB,CAAC;gCAC3B,CAAC;4BACH,CAAC,CAAC,CAAC;wBAEL,OAAO,iBAAiB,CAAC;oBAC3B,CAAC,CAAC,CAAC;gBACL,OAAO,mBAAmB,CAAC;YAC7B,CAAC,CAAC,CAAC;QACL,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,WAAW;YACtB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,yEAAyE;QACzE,sBAAsB;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;SAAM,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;QACzC,MAAM,iBAAiB,GAAQ,EAAE,CAAC;QAClC,iDAAiD;QACjD,iBAAiB,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAC/C,IAAI,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC;YACtE,iBAAiB,CAAC,QAAQ,GAAG,EAAE,CAAC;YAChC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAC9B,IAAI;gBACJ,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ;gBACvC,MAAM,EAAE;oBACN,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK;oBACjC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM;iBACpC;gBACD,QAAQ,EAAE;oBACR,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc;oBAC1C,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe;iBAC7C;aACF,CAAC,CAAC;QACL,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,YAAY;YACvB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;SAAM,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;QACzC,IAAI,iBAAsB,CAAC;QAC3B,iDAAiD;QACjD,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,kBAAkB,EAAE,GAAG,MAAM,CAAC;QAC/D,kBAAkB,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACtC,kBAAkB,CAAC,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC;QACnD,iBAAiB,GAAG,EAAE,GAAG,kBAAkB,EAAE,CAAC;QAE9C,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,YAAY;YACvB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,iBAAiB,CAAC;IAC3B,CAAC;SAAM,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QACtC,2CAA2C;QAC3C,MAAM,iBAAiB,GAAQ;YAC7B,MAAM,EAAE,MAAM,CAAC,EAAE;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,WAAW,EAAE,MAAM,CAAC,IAAI;SACzB,CAAC;QACF,IAAI,MAAM,CAAC,QAAQ;YACjB,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAY,EAAE,EAAE,CAC7D,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,OAAO;aAChB,CAAC,CACH,CAAC;QACJ,IAAI,MAAM,CAAC,OAAO;YAChB,iBAAiB,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,WAAgB,EAAE,EAAE,CAClE,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,WAAW;aACpB,CAAC,CACH,CAAC;QACJ,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CACvD,oBAAoB,CAAC;YACnB,aAAa,EAAE,SAAS;YACxB,YAAY,EAAE,SAAS;YACvB,MAAM,EAAE,IAAI;SACb,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,SAAS;YACpB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,6DAA6D;QAC7D,sBAAsB;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;SAAM,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QACtC,2CAA2C;QAC3C,MAAM,iBAAiB,GAAQ;YAC7B,MAAM,EAAE,MAAM,CAAC,EAAE;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,WAAW,EAAE,MAAM,CAAC,IAAI;YACxB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,MAAM,EAAE,MAAM,CAAC,KAAK;YACpB,KAAK,EAAE,MAAM,CAAC,OAAO;SACtB,CAAC;QACF,IAAI,MAAM,CAAC,QAAQ;YACjB,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAY,EAAE,EAAE,CAC7D,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,OAAO;aAChB,CAAC,CACH,CAAC;QACJ,IAAI,MAAM,CAAC,OAAO;YAChB,iBAAiB,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,WAAgB,EAAE,EAAE,CAClE,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,WAAW;aACpB,CAAC,CACH,CAAC;QACJ,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CACvD,oBAAoB,CAAC;YACnB,aAAa,EAAE,GAAG,IAAI,CAAC,MAAM,KAAK;YAClC,YAAY,EAAE,SAAS;YACvB,MAAM,EAAE,IAAI;SACb,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,SAAS;YACpB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,6DAA6D;QAC7D,sBAAsB;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;IACD,4EAA4E;IAC5E,OAAO,IAAI,CAAC;AACd,CAAC"} \ No newline at end of file +{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":";;;;;AAoGA,4BAkGC;AAYD,oDAgZC;AAlmBD,uCAA+C;AAC/C,8CAA4C;AAC5C,kEAAkE;AAClE,8DAAqC;AACrC,oEAAoE;AACpE,gEAAuC;AACvC,iEAAiE;AACjE,4DAAmC;AACnC,mCAAoC;AAEpC,qBAAqB;AACrB,MAAM,GAAG,GAAG,IAAI,aAAG,CAAC;IAClB,YAAY,EAAE,KAAK;IACnB,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,IAAI;IACf,eAAe,EAAE,IAAI;IACrB,WAAW,EAAE,IAAI;CAClB,CAAC,CAAC;AAEH,gCAAgC;AAChC,qEAAqE;AACrE,MAAM,GAAG,GAAG,OAAO,CAAC,+CAA+C,CAAC,CAAC;AACrE,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC,mBAAU,CAAC;AAErC,cAAc;AACd,IAAA,qBAAU,EAAC,GAAG,CAAC,CAAC;AAChB,IAAA,sBAAW,EAAC,GAAG,CAAC,CAAC;AACjB,IAAA,oBAAS,EAAC,GAAG,CAAC,CAAC;AAEf,wCAAwC;AACxC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,iBAAO,CAAC,EAAE,CAAC;IACnD,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,+DAA+D;AAC/D,MAAM,iBAAiB,GAAG;IACxB,SAAS,EAAE,CAAC,WAAW,CAAC;IACxB,UAAU,EAAE,CAAC,YAAY,CAAC;IAC1B,UAAU,EAAE,CAAC,YAAY,CAAC;IAC1B,OAAO,EAAE,CAAC,SAAS,CAAC;IACpB,OAAO,EAAE;QACP,cAAc;QACd,SAAS;QACT,SAAS;QACT,gBAAgB;QAChB,aAAa;QACb,YAAY;QACZ,mBAAmB;QACnB,iBAAiB;QACjB,mBAAmB;QACnB,kBAAkB;QAClB,aAAa;QACb,SAAS;KACV;IACD,OAAO,EAAE,CAAC,SAAS,CAAC;CACZ,CAAC;AAsBX;;;;;GAKG;AACH,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC,oCAAoC;AAC5F,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,MAAM,EACN,WAAW,GAAG,IAAI,GACF;IAChB,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,MAAM,GAAmB;QAC7B,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,MAAM;KACf,CAAC;IACF,IAAI,gBAAqB,CAAC;IAC1B,IAAI,KAAK,GAAiC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACnE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,MAAM,CAAC,MAAM,GAAG,qBAAqB,SAAS,EAAE,CAAC;QACjD,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,0DAA0D;IAC1D,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAEtD,oDAAoD;IACpD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACvC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;IAEnB,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,wDAAwD;QACxD,MAAM,qBAAqB,GACzB,iBAAiB,CAAC,SAA2C,CAAC,CAAC;QACjE,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC3B,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;iBACzB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CACR,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,SAAS,CACvD,KAAK,CAAC,MAAM,CACb,GAAG,CACP;iBACA,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;YACrB,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YAC1D,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;YACtD,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,KAAK,IAAI,KAAK,CAAC,gBAAgB,CAAC;gBAAE,OAAO,GAAG,CAAC;QACnD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;iBACzB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CACR,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,SAAS,CACvD,KAAK,CAAC,MAAM,CACb,GAAG,CACP;iBACA,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;YACrB,OAAO,MAAM,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,MAAM,iBAAiB,GAAG,oBAAoB,CAAC;gBAC7C,aAAa,EAAE,gBAAgB;gBAC/B,YAAY,EAAE,SAAS;gBACvB,MAAM,EAAE,gBAAgB;aACzB,CAAC,CAAC;YAEH,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACxC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,gBAAgB,GAAG,iBAAiB,CAAC;gBACrC,MAAM,GAAG,iBAAiB,CAAC;gBAC3B,oGAAoG;YACtG,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAC7B,CAAC,KAAK,EAAE,EAAE,CACR,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,SAAS,CACvD,KAAK,CAAC,MAAM,CACb,GAAG,CACP,CAAC;gBACF,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClC,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,oBAAoB;QACtB,CAAC;IACH,CAAC;IACD,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,MAAM,GAAG,gBAAgB,CAAC;IACnC,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,oBAAoB,CAAC,EACnC,aAAa,GAAG,EAAE,EAClB,YAAY,GAAG,EAAE,EACjB,MAAM,GAAG,EAAE,GACM;IACjB,+DAA+D;IAC/D,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;QACnC,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,mEAAmE;IACnE,MAAM,cAAc,GAAG,iBAAiB,CAAC,YAAmC,CAAC,CAAC;IAC9E,IACE,CAAC,cAAc;QACf,CAAE,cAAoC,CAAC,QAAQ,CAAC,aAAa,CAAC,EAC9D,CAAC;QACD,MAAM,IAAI,KAAK,CACb,wBAAwB,aAAa,OAAO,YAAY,GAAG,CAC5D,CAAC;IACJ,CAAC;IACD,uBAAuB;IACvB,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,iBAAiB,GAAQ;YAC7B,MAAM,EAAE,MAAM,CAAC,EAAE;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;SAChC,CAAC;QACF,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,iBAAiB,CAAC,IAAI,GAAG;gBACvB,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,cAAc,EAAE,CAAC;YAC5C,iBAAiB,CAAC,SAAS,GAAG;gBAC5B,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,WAAW,EAAE,MAAM,CAAC,WAAW;aAChC,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YACvC,iBAAiB,CAAC,IAAI,GAAG;gBACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,WAAW,EAAE,MAAM,CAAC,SAAS;gBAC7B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,IAAI,EAAE,MAAM,CAAC,QAAQ;aACtB,CAAC;YACF,mCAAmC;YACnC,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAChE,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAC/D,OAAO,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;YAC3C,CAAC;YACD,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAC;YACjC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE;gBAC7C,iBAAiB,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACxC,4BAA4B,QAAQ,CAAC,KAAK,IAAI,CAAC;YACnD,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,aAAa,KAAK,gBAAgB,EAAE,CAAC;YAC9C,iBAAiB,CAAC,WAAW,GAAG;gBAC9B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM,CAAC,WAAW;oBACxB,OAAO,EAAE,MAAM,CAAC,cAAc;oBAC9B,UAAU,EAAE,MAAM,CAAC,aAAa;iBACjC;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,MAAM,CAAC,YAAY;oBACzB,OAAO,EAAE,MAAM,CAAC,eAAe;iBAChC;gBACD,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;gBACnD,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,SAAS,EAAE,MAAM,CAAC,aAAa;gBAC/B,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,GAAG;gBACvC,SAAS,EACP,MAAM,CAAC,SAAS,KAAK,aAAa;oBAChC,CAAC,CAAC,gBAAgB;oBAClB,CAAC,CAAC,MAAM,CAAC,SAAS;aACvB,CAAC;YACF,2CAA2C;YAC3C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,iBAAiB,CAAC,WAAW,CAAC,OAAO,GAAG,oBAAoB,CAAC;oBAC3D,aAAa,EAAE,YAAY;oBAC3B,YAAY,EAAE,YAAY;oBAC1B,MAAM,EAAE,MAAM,CAAC,OAAO;iBACvB,CAAC,CAAC;YACL,CAAC;YACD,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAC;YACjC,MAAM,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE;gBACrD,iBAAiB,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACxC,wBAAwB,QAAQ,CAAC,QAAQ,IAAI,CAAC;YAClD,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,aAAa,KAAK,aAAa,EAAE,CAAC;YAC3C,iBAAiB,CAAC,QAAQ,GAAG;gBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;gBACzC,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,MAAM;gBACpB,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,SAAS,EAAE,MAAM,CAAC,aAAa;gBAC/B,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,GAAG;gBACvC,SAAS,EACP,MAAM,CAAC,SAAS,KAAK,aAAa;oBAChC,CAAC,CAAC,gBAAgB;oBAClB,CAAC,CAAC,MAAM,CAAC,SAAS;gBACtB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC;YACF,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAC;YACjC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE;gBAC7C,iBAAiB,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACxC,4BAA4B,QAAQ,CAAC,KAAK,IAAI,CAAC;YACnD,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;YAC1C,iBAAiB,CAAC,OAAO,GAAG;gBAC1B,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;gBACzC,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,MAAM;gBACpB,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,SAAS,EAAE,MAAM,CAAC,aAAa;gBAC/B,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,GAAG;gBACvC,SAAS,EACP,MAAM,CAAC,SAAS,KAAK,aAAa;oBAChC,CAAC,CAAC,gBAAgB;oBAClB,CAAC,CAAC,MAAM,CAAC,SAAS;gBACtB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC;YACF,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAC;YACjC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE;gBAC9C,iBAAiB,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACxC,4BAA4B,QAAQ,CAAC,KAAK,IAAI,CAAC;YACnD,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,aAAa,KAAK,iBAAiB,EAAE,CAAC;YAC/C,iBAAiB,CAAC,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC;QAChD,CAAC;aAAM,IAAI,aAAa,KAAK,aAAa,EAAE,CAAC;YAC3C,iBAAiB,CAAC,IAAI,GAAG;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,UAAU,EAAE,MAAM,CAAC,KAAK;aACzB,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,mBAAmB,EAAE,CAAC;YACjD,iBAAiB,CAAC,UAAU,GAAG;gBAC7B,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,GAAG;gBACvC,SAAS,EACP,MAAM,CAAC,SAAS,KAAK,aAAa;oBAChC,CAAC,CAAC,gBAAgB;oBAClB,CAAC,CAAC,MAAM,CAAC,SAAS;gBACtB,IAAI,EAAE,MAAM,CAAC,IAAI;aAClB,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,mBAAmB,EAAE,CAAC;YACjD,iBAAiB,CAAC,MAAM,GAAG;gBACzB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;aAC5B,CAAC;QACJ,CAAC;aAAM,IAAI,aAAa,KAAK,kBAAkB,EAAE,CAAC;YAChD,iBAAiB,CAAC,UAAU,GAAG,IAAI,CAAC;QACtC,CAAC;aAAM,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YACvC,iBAAiB,CAAC,IAAI,GAAG,MAAM,CAAC;QAClC,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,SAAS;YACpB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;SAAM,IAAI,YAAY,KAAK,WAAW,EAAE,CAAC;QACxC,+CAA+C;QAC/C,MAAM,iBAAiB,GAAQ;YAC7B,aAAa,EAAE,MAAM,CAAC,YAAY;YAClC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI,MAAM,CAAC,KAAK;YAC9C,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,MAAM,CAAC,MAAM;YACjD,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,IAAI,MAAM,CAAC,SAAS;YAC1D,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;YACzC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW;YAC1C,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK;YAClC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO;YACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,SAAS,EAAE,MAAM,CAAC,SAAS;SAC5B,CAAC;QACF,gCAAgC;QAChC,IAAI,MAAM,EAAE,QAAQ,EAAE,QAAQ;YAC5B,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAY,EAAE,EAAE,CACtE,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,OAAO;aAChB,CAAC,CACH,CAAC;QACJ,gCAAgC;QAChC,IAAI,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;YAClC,iBAAiB,CAAC,YAAY,GAAG,EAAE,CAAC;YACpC,iBAAiB,CAAC,YAAY,CAAC,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CACtE,CAAC,WAAgB,EAAE,EAAE,CACnB,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,WAAW;aACpB,CAAC,CACL,CAAC;QACJ,CAAC;QACD,kCAAkC;QAClC,IAAI,MAAM,EAAE,SAAS;YACnB,iBAAiB,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAa,EAAE,EAAE;gBACnE,MAAM,mBAAmB,GAAQ;oBAC/B,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAiB,EAAE,EAAE;oBACxD,kCAAkC;oBAClC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAC7B;oBACD,gBAAgB,EAAE;wBAChB,wDAAwD;wBACxD,SAAS,EAAE,GAAG,YAAY,CACxB,QAAQ,CAAC,sBAAsB,CAChC,QAAQ,YAAY,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE;wBACzD,OAAO,EAAE,YAAY,CAAC,QAAQ,CAAC,gBAAgB,CAAC;wBAChD,WAAW,EAAE,YAAY,CAAC,QAAQ,CAAC,mBAAmB,CAAC;wBACvD,IAAI,EAAE,GAAG,YAAY,CACnB,QAAQ,CAAC,iBAAiB,CAC3B,QAAQ,YAAY,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE;qBACrD;iBACF,CAAC;gBACF,IAAI,QAAQ,CAAC,MAAM;oBACjB,mBAAmB,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAW,EAAE,EAAE;wBAC/D,MAAM,iBAAiB,GAAQ;4BAC7B,IAAI,EAAE,MAAM,CAAC,IAAI;4BACjB,KAAK,EAAE,MAAM,CAAC,KAAK;yBACpB,CAAC;wBACF,IAAI,MAAM,CAAC,OAAO;4BAChB,iBAAiB,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAW,EAAE,EAAE;gCAC7D,IAAI,OAAO,MAAM,KAAK,QAAQ;oCAAE,OAAO,MAAM,CAAC;gCAC9C,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;oCAC/B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;wCAClB,MAAM,GAAG;4CACP,MAAM,EAAE,MAAM,CAAC,IAAI;4CACnB,GAAG,MAAM,CAAC,MAAM;yCACjB,CAAC;oCACJ,CAAC;oCACD,MAAM,iBAAiB,GAAG,oBAAoB,CAAC;wCAC7C,aAAa,EAAE,GAAG,MAAM,CAAC,MAAM,KAAK;wCACpC,YAAY,EAAE,SAAS;wCACvB,MAAM,EAAE,MAAM;qCACf,CAAC,CAAC;oCACH,OAAO,iBAAiB,CAAC;gCAC3B,CAAC;4BACH,CAAC,CAAC,CAAC;wBAEL,OAAO,iBAAiB,CAAC;oBAC3B,CAAC,CAAC,CAAC;gBACL,OAAO,mBAAmB,CAAC;YAC7B,CAAC,CAAC,CAAC;QACL,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,WAAW;YACtB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,yEAAyE;QACzE,sBAAsB;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;SAAM,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;QACzC,MAAM,iBAAiB,GAAQ,EAAE,CAAC;QAClC,iDAAiD;QACjD,iBAAiB,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAC/C,IAAI,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC;YACtE,iBAAiB,CAAC,QAAQ,GAAG,EAAE,CAAC;YAChC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAC9B,IAAI;gBACJ,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ;gBACvC,MAAM,EAAE;oBACN,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK;oBACjC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM;iBACpC;gBACD,QAAQ,EAAE;oBACR,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc;oBAC1C,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe;iBAC7C;aACF,CAAC,CAAC;QACL,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,YAAY;YACvB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;SAAM,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;QACzC,IAAI,iBAAsB,CAAC;QAC3B,iDAAiD;QACjD,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,kBAAkB,EAAE,GAAG,MAAM,CAAC;QAC/D,kBAAkB,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACtC,kBAAkB,CAAC,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC;QACnD,iBAAiB,GAAG,EAAE,GAAG,kBAAkB,EAAE,CAAC;QAE9C,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,YAAY;YACvB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,iBAAiB,CAAC;IAC3B,CAAC;SAAM,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QACtC,2CAA2C;QAC3C,MAAM,iBAAiB,GAAQ;YAC7B,MAAM,EAAE,MAAM,CAAC,EAAE;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,WAAW,EAAE,MAAM,CAAC,IAAI;SACzB,CAAC;QACF,IAAI,MAAM,CAAC,QAAQ;YACjB,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAY,EAAE,EAAE,CAC7D,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,OAAO;aAChB,CAAC,CACH,CAAC;QACJ,IAAI,MAAM,CAAC,OAAO;YAChB,iBAAiB,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,WAAgB,EAAE,EAAE,CAClE,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,WAAW;aACpB,CAAC,CACH,CAAC;QACJ,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CACvD,oBAAoB,CAAC;YACnB,aAAa,EAAE,SAAS;YACxB,YAAY,EAAE,SAAS;YACvB,MAAM,EAAE,IAAI;SACb,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,SAAS;YACpB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,6DAA6D;QAC7D,sBAAsB;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;SAAM,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QACtC,2CAA2C;QAC3C,MAAM,iBAAiB,GAAQ;YAC7B,MAAM,EAAE,MAAM,CAAC,EAAE;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,WAAW,EAAE,MAAM,CAAC,IAAI;YACxB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,MAAM,EAAE,MAAM,CAAC,KAAK;YACpB,KAAK,EAAE,MAAM,CAAC,OAAO;SACtB,CAAC;QACF,IAAI,MAAM,CAAC,QAAQ;YACjB,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAY,EAAE,EAAE,CAC7D,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,OAAO;aAChB,CAAC,CACH,CAAC;QACJ,IAAI,MAAM,CAAC,OAAO;YAChB,iBAAiB,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,WAAgB,EAAE,EAAE,CAClE,oBAAoB,CAAC;gBACnB,aAAa,EAAE,YAAY;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,MAAM,EAAE,WAAW;aACpB,CAAC,CACH,CAAC;QACJ,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CACvD,oBAAoB,CAAC;YACnB,aAAa,EAAE,GAAG,IAAI,CAAC,MAAM,KAAK;YAClC,YAAY,EAAE,SAAS;YACvB,MAAM,EAAE,IAAI;SACb,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC;YACtB,SAAS,EAAE,SAAS;YACpB,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;QACH,6DAA6D;QAC7D,sBAAsB;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;IACD,4EAA4E;IAC5E,OAAO,IAAI,CAAC;AACd,CAAC"} \ No newline at end of file diff --git a/src/validate.ts b/src/validate.ts index 6c9a7b7e..e772dacc 100644 --- a/src/validate.ts +++ b/src/validate.ts @@ -32,9 +32,8 @@ for (const [key, value] of Object.entries(schemas)) { ajv.addSchema(value, key); } -type CompatibleSchemaKey = keyof typeof compatibleSchemas; - -const compatibleSchemas: Partial> = { +// Define the specific schemas that have compatibility mappings +const compatibleSchemas = { config_v3: ["config_v2"], context_v3: ["context_v2"], openApi_v3: ["openApi_v2"], @@ -54,7 +53,9 @@ const compatibleSchemas: Partial> = { "wait_v2", ], test_v3: ["test_v2"], -}; +} as const; + +type CompatibleSchemaKey = keyof typeof compatibleSchemas; export interface ValidateOptions { schemaKey: string; @@ -97,7 +98,11 @@ function escapeRegExp(string: string): string { * * @throws {Error} If {@link schemaKey} or {@link object} is missing. */ -export function validate({ schemaKey, object, addDefaults = true }: ValidateOptions): ValidateResult { +export function validate({ + schemaKey, + object, + addDefaults = true, +}: ValidateOptions): ValidateResult { if (!schemaKey) { throw new Error("Schema key is required."); } @@ -127,14 +132,15 @@ export function validate({ schemaKey, object, addDefaults = true }: ValidateOpti if (check.errors) { // Check if the object is compatible with another schema - const compatibleSchemasList = compatibleSchemas[schemaKey as keyof typeof compatibleSchemas]; + const compatibleSchemasList = + compatibleSchemas[schemaKey as keyof typeof compatibleSchemas]; if (!compatibleSchemasList) { result.errors = check.errors .map( (error) => `${error.instancePath} ${error.message} (${JSON.stringify( - error.params - )})` + error.params, + )})`, ) .join(", "); result.object = object; @@ -151,8 +157,8 @@ export function validate({ schemaKey, object, addDefaults = true }: ValidateOpti .map( (error) => `${error.instancePath} ${error.message} (${JSON.stringify( - error.params - )})` + error.params, + )})`, ) .join(", "); result.object = object; @@ -174,8 +180,8 @@ export function validate({ schemaKey, object, addDefaults = true }: ValidateOpti const errors = check.errors.map( (error) => `${error.instancePath} ${error.message} (${JSON.stringify( - error.params - )})` + error.params, + )})`, ); result.errors = errors.join(", "); return result; @@ -212,9 +218,13 @@ export function transformToSchemaKey({ return object; } // Check if the current schema is compatible with the target schema - if (!compatibleSchemas[targetSchema as keyof typeof compatibleSchemas]?.includes(currentSchema as any)) { + const compatibleList = compatibleSchemas[targetSchema as CompatibleSchemaKey]; + if ( + !compatibleList || + !(compatibleList as readonly string[]).includes(currentSchema) + ) { throw new Error( - `Can't transform from ${currentSchema} to ${targetSchema}.` + `Can't transform from ${currentSchema} to ${targetSchema}.`, ); } // Transform the object @@ -250,9 +260,8 @@ export function transformToSchemaKey({ } transformedObject.variables = {}; object.setVariables?.forEach((variable: any) => { - transformedObject.variables[ - variable.name - ] = `extract($$element.text, "${variable.regex}")`; + transformedObject.variables[variable.name] = + `extract($$element.text, "${variable.regex}")`; }); } else if (currentSchema === "httpRequest_v2") { transformedObject.httpRequest = { @@ -289,9 +298,8 @@ export function transformToSchemaKey({ } transformedObject.variables = {}; object.envsFromResponseData?.forEach((variable: any) => { - transformedObject.variables[ - variable.name - ] = `jq($$response.body, "${variable.jqFilter}")`; + transformedObject.variables[variable.name] = + `jq($$response.body, "${variable.jqFilter}")`; }); } else if (currentSchema === "runShell_v2") { transformedObject.runShell = { @@ -311,9 +319,8 @@ export function transformToSchemaKey({ }; transformedObject.variables = {}; object.setVariables?.forEach((variable: any) => { - transformedObject.variables[ - variable.name - ] = `extract($$stdio.stdout, "${variable.regex}")`; + transformedObject.variables[variable.name] = + `extract($$stdio.stdout, "${variable.regex}")`; }); } else if (currentSchema === "runCode_v2") { transformedObject.runCode = { @@ -334,9 +341,8 @@ export function transformToSchemaKey({ }; transformedObject.variables = {}; object?.setVariables?.forEach((variable: any) => { - transformedObject.variables[ - variable.name - ] = `extract($$stdio.stdout, "${variable.regex}")`; + transformedObject.variables[variable.name] = + `extract($$stdio.stdout, "${variable.regex}")`; }); } else if (currentSchema === "setVariables_v2") { transformedObject.loadVariables = object.path; @@ -396,7 +402,7 @@ export function transformToSchemaKey({ currentSchema: "context_v2", targetSchema: "context_v3", object: context, - }) + }), ); // Handle openApi transformation if (object?.integrations?.openApi) { @@ -407,7 +413,7 @@ export function transformToSchemaKey({ currentSchema: "openApi_v2", targetSchema: "openApi_v3", object: description, - }) + }), ); } // Handle fileTypes transformation @@ -417,17 +423,17 @@ export function transformToSchemaKey({ name: fileType.name, extensions: fileType.extensions.map((extension: string) => // Trim leading `.` from extension - extension.replace(/^\./, "") + extension.replace(/^\./, ""), ), inlineStatements: { // Convert strings to regex, escaping special characters testStart: `${escapeRegExp( - fileType.testStartStatementOpen + fileType.testStartStatementOpen, )}(.*?)${escapeRegExp(fileType.testStartStatementClose)}`, testEnd: escapeRegExp(fileType.testEndStatement), ignoreStart: escapeRegExp(fileType.testIgnoreStatement), step: `${escapeRegExp( - fileType.stepStatementOpen + fileType.stepStatementOpen, )}(.*?)${escapeRegExp(fileType.stepStatementClose)}`, }, }; @@ -527,7 +533,7 @@ export function transformToSchemaKey({ currentSchema: "context_v2", targetSchema: "context_v3", object: context, - }) + }), ); if (object.openApi) transformedObject.openApi = object.openApi.map((description: any) => @@ -535,14 +541,14 @@ export function transformToSchemaKey({ currentSchema: "openApi_v2", targetSchema: "openApi_v3", object: description, - }) + }), ); transformedObject.tests = object.tests.map((test: any) => transformToSchemaKey({ currentSchema: "test_v2", targetSchema: "test_v3", object: test, - }) + }), ); const result = validate({ @@ -571,7 +577,7 @@ export function transformToSchemaKey({ currentSchema: "context_v2", targetSchema: "context_v3", object: context, - }) + }), ); if (object.openApi) transformedObject.openApi = object.openApi.map((description: any) => @@ -579,14 +585,14 @@ export function transformToSchemaKey({ currentSchema: "openApi_v2", targetSchema: "openApi_v3", object: description, - }) + }), ); transformedObject.steps = object.steps.map((step: any) => transformToSchemaKey({ currentSchema: `${step.action}_v2`, targetSchema: "step_v3", object: step, - }) + }), ); const result = validate({ From 7e00fec7e92e76fd2ba49fcfafd2196ca7d80b41 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 26 Jan 2026 15:06:21 -0800 Subject: [PATCH 4/4] fix: address PR review comments and fix CI coverage - Fix coverage config to measure dist/ instead of src/ - Update CI workflow to build before coverage check - Add integration tests for CJS and ESM imports - Fix bare URLs in docs (MD034) - Add error tracking to generateTypes.js - Ensure dist directory exists in createEsmWrapper.js - Fix openApi_v3 transformation to return result.object - Add test for invalid objectType error - Fix c8 ignore comment coverage --- .c8rc.json | 4 +- .github/workflows/npm-test.yml | 2 +- dist/validate.js | 4 +- dist/validate.js.map | 2 +- docs/typescript-migration.md | 4 +- plans/plan-typescriptMigration.prompt.md | 2 +- scripts/createEsmWrapper.js | 3 + scripts/generateTypes.js | 9 + src/validate.ts | 4 +- test/integration.test.js | 215 +++++++++++++++++++++++ test/resolvePaths.test.js | 14 ++ 11 files changed, 252 insertions(+), 11 deletions(-) create mode 100644 test/integration.test.js diff --git a/.c8rc.json b/.c8rc.json index 5615029d..88b1a167 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -1,7 +1,7 @@ { "all": true, - "include": ["src/**/*.js"], - "exclude": ["src/schemas/dereferenceSchemas.js"], + "include": ["dist/**/*.js"], + "exclude": ["dist/types/generated/**/*.js", "dist/**/*.d.ts"], "reporter": ["text", "lcov", "json", "json-summary"], "report-dir": "coverage", "check-coverage": false diff --git a/.github/workflows/npm-test.yml b/.github/workflows/npm-test.yml index 83e360ee..81419be2 100644 --- a/.github/workflows/npm-test.yml +++ b/.github/workflows/npm-test.yml @@ -50,7 +50,7 @@ jobs: cache-dependency-path: package-lock.json node-version: 20 - run: npm ci - - run: npm run dereferenceSchemas + - run: npm run dereferenceSchemas && npm run generate:types && npm run compile - name: Run tests with coverage run: npm run test:coverage - name: Check coverage ratchet diff --git a/dist/validate.js b/dist/validate.js index 773d647c..00cedc79 100644 --- a/dist/validate.js +++ b/dist/validate.js @@ -468,7 +468,7 @@ function transformToSchemaKey({ currentSchema = "", targetSchema = "", object = if (!result.valid) { throw new Error(`Invalid object: ${result.errors}`); } - return transformedObject; + return result.object; } else if (targetSchema === "spec_v3") { // Handle spec_v2 to spec_v3 transformation @@ -543,7 +543,7 @@ function transformToSchemaKey({ currentSchema = "", targetSchema = "", object = } return result.object; } - /* c8 ignore next - Dead code: incompatible schemas throw at line 197-200 */ + /* c8 ignore next 2 - Dead code: incompatible schemas throw at line 226-228 */ return null; } //# sourceMappingURL=validate.js.map \ No newline at end of file diff --git a/dist/validate.js.map b/dist/validate.js.map index 12897d2e..97519809 100644 --- a/dist/validate.js.map +++ b/dist/validate.js.map @@ -1 +1 @@ -{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/docs/typescript-migration.md b/docs/typescript-migration.md index fdd226e6..597a1391 100644 --- a/docs/typescript-migration.md +++ b/docs/typescript-migration.md @@ -566,8 +566,8 @@ async function processSpecFile(path: string) { ## Need Help? -- **Issues**: Report bugs or request features at https://github.com/doc-detective/doc-detective-common/issues -- **Discussions**: Ask questions at https://github.com/doc-detective/doc-detective-common/discussions +- **Issues**: Report bugs or request features at [GitHub Issues](https://github.com/doc-detective/doc-detective-common/issues) +- **Discussions**: Ask questions at [GitHub Discussions](https://github.com/doc-detective/doc-detective-common/discussions) - **Documentation**: See main [README.md](../README.md) for general usage ## Version Compatibility diff --git a/plans/plan-typescriptMigration.prompt.md b/plans/plan-typescriptMigration.prompt.md index 591b75ed..6ae55bed 100644 --- a/plans/plan-typescriptMigration.prompt.md +++ b/plans/plan-typescriptMigration.prompt.md @@ -14,7 +14,7 @@ A phased approach to convert this CommonJS JavaScript library to TypeScript, lev 5. **Convert high-complexity** [src/validate.ts](src/validate.js) — split 350+ line `transformToSchemaKey()` into modular transformation functions, type the `compatibleSchemas` map, and use generic `validate()` signature -6. **Update build pipeline** in [dereferenceSchemas.js](src/schemas/dereferenceSchemas.js) — add `tsc` compilation step before schema dereference, update CI workflows to run TypeScript build +6. **Update build pipeline** — ensure schema dereference runs before generate:types and compile (pipeline order: `dereferenceSchemas → generate:types → compile`), and update CI workflows to run the TypeScript build ### Further Considerations diff --git a/scripts/createEsmWrapper.js b/scripts/createEsmWrapper.js index d680826a..e7e54c6e 100644 --- a/scripts/createEsmWrapper.js +++ b/scripts/createEsmWrapper.js @@ -4,6 +4,9 @@ const path = require("path"); async function createEsmWrapper() { const distDir = path.join(__dirname, "..", "dist"); + // Ensure dist directory exists + await fs.mkdir(distDir, { recursive: true }); + // Create ESM wrapper that re-exports from CJS const esmContent = `// ESM wrapper for CommonJS output import cjsModule from './index.js'; diff --git a/scripts/generateTypes.js b/scripts/generateTypes.js index 36ce85fa..25935367 100644 --- a/scripts/generateTypes.js +++ b/scripts/generateTypes.js @@ -15,6 +15,9 @@ async function generateTypes() { console.log(`Generating TypeScript types for ${v3Schemas.length} schemas...`); + let hadErrors = false; + const failedFiles = []; + for (const file of v3Schemas) { const schemaPath = path.join(schemasDir, file); const schema = JSON.parse(await fs.readFile(schemaPath, "utf-8")); @@ -32,10 +35,16 @@ async function generateTypes() { await fs.writeFile(outputPath, ts); console.log(` ✓ ${file} → ${path.basename(outputPath)}`); } catch (error) { + hadErrors = true; + failedFiles.push(file); console.error(` ✗ Failed to generate ${file}:`, error.message); } } + if (hadErrors) { + throw new Error(`One or more schemas failed to generate TypeScript types: ${failedFiles.join(", ")}`); + } + console.log("Type generation complete!"); } diff --git a/src/validate.ts b/src/validate.ts index e772dacc..68e660e3 100644 --- a/src/validate.ts +++ b/src/validate.ts @@ -519,7 +519,7 @@ export function transformToSchemaKey({ if (!result.valid) { throw new Error(`Invalid object: ${result.errors}`); } - return transformedObject; + return result.object; } else if (targetSchema === "spec_v3") { // Handle spec_v2 to spec_v3 transformation const transformedObject: any = { @@ -606,6 +606,6 @@ export function transformToSchemaKey({ } return result.object; } - /* c8 ignore next - Dead code: incompatible schemas throw at line 197-200 */ + /* c8 ignore next 2 - Dead code: incompatible schemas throw at line 226-228 */ return null; } diff --git a/test/integration.test.js b/test/integration.test.js new file mode 100644 index 00000000..a0b80138 --- /dev/null +++ b/test/integration.test.js @@ -0,0 +1,215 @@ +/** + * Integration tests to verify both CommonJS and ESM module exports work correctly. + * These tests verify that the package can be consumed via both module systems. + */ + +(async () => { + const { expect } = await import("chai"); + const path = require("path"); + const { execSync } = require("child_process"); + + describe("Module Integration Tests", function () { + // Increase timeout for spawning node processes + this.timeout(10000); + + describe("CommonJS (require)", function () { + it("should export validate function via require", function () { + const { validate } = require("../dist/index.js"); + expect(typeof validate).to.equal("function"); + }); + + it("should export transformToSchemaKey function via require", function () { + const { transformToSchemaKey } = require("../dist/index.js"); + expect(typeof transformToSchemaKey).to.equal("function"); + }); + + it("should export resolvePaths function via require", function () { + const { resolvePaths } = require("../dist/index.js"); + expect(typeof resolvePaths).to.equal("function"); + }); + + it("should export readFile function via require", function () { + const { readFile } = require("../dist/index.js"); + expect(typeof readFile).to.equal("function"); + }); + + it("should export schemas object via require", function () { + const { schemas } = require("../dist/index.js"); + expect(typeof schemas).to.equal("object"); + expect(schemas).to.have.property("step_v3"); + expect(schemas).to.have.property("config_v3"); + }); + + it("should validate a step using CJS imports", function () { + const { validate } = require("../dist/index.js"); + const result = validate({ + schemaKey: "step_v3", + object: { + goTo: { url: "https://example.com" }, + }, + }); + expect(result.valid).to.be.true; + expect(result.object.goTo.url).to.equal("https://example.com"); + }); + + it("should work with default export via require", function () { + const docDetectiveCommon = require("../dist/index.js"); + expect(typeof docDetectiveCommon.validate).to.equal("function"); + expect(typeof docDetectiveCommon.schemas).to.equal("object"); + }); + }); + + describe("ESM (import)", function () { + it("should export validate function via ESM import", async function () { + // Use dynamic import to test ESM wrapper + const module = await import("../dist/index.mjs"); + expect(typeof module.validate).to.equal("function"); + }); + + it("should export transformToSchemaKey function via ESM import", async function () { + const module = await import("../dist/index.mjs"); + expect(typeof module.transformToSchemaKey).to.equal("function"); + }); + + it("should export resolvePaths function via ESM import", async function () { + const module = await import("../dist/index.mjs"); + expect(typeof module.resolvePaths).to.equal("function"); + }); + + it("should export readFile function via ESM import", async function () { + const module = await import("../dist/index.mjs"); + expect(typeof module.readFile).to.equal("function"); + }); + + it("should export schemas object via ESM import", async function () { + const module = await import("../dist/index.mjs"); + expect(typeof module.schemas).to.equal("object"); + expect(module.schemas).to.have.property("step_v3"); + expect(module.schemas).to.have.property("config_v3"); + }); + + it("should validate a step using ESM imports", async function () { + const { validate } = await import("../dist/index.mjs"); + const result = validate({ + schemaKey: "step_v3", + object: { + goTo: { url: "https://example.com" }, + }, + }); + expect(result.valid).to.be.true; + expect(result.object.goTo.url).to.equal("https://example.com"); + }); + + it("should have default export via ESM import", async function () { + const module = await import("../dist/index.mjs"); + expect(module.default).to.exist; + expect(typeof module.default.validate).to.equal("function"); + }); + }); + + describe("Cross-module compatibility", function () { + it("should produce identical validation results from CJS and ESM", async function () { + const cjsModule = require("../dist/index.js"); + const esmModule = await import("../dist/index.mjs"); + + const testObject = { + goTo: { url: "https://example.com" }, + }; + + const cjsResult = cjsModule.validate({ + schemaKey: "step_v3", + object: JSON.parse(JSON.stringify(testObject)), + }); + + const esmResult = esmModule.validate({ + schemaKey: "step_v3", + object: JSON.parse(JSON.stringify(testObject)), + }); + + expect(cjsResult.valid).to.equal(esmResult.valid); + // Note: stepId is generated with UUID, so we compare other properties + expect(cjsResult.object.goTo).to.deep.equal(esmResult.object.goTo); + }); + + it("should have the same schema keys in CJS and ESM exports", async function () { + const cjsModule = require("../dist/index.js"); + const esmModule = await import("../dist/index.mjs"); + + const cjsSchemaKeys = Object.keys(cjsModule.schemas).sort(); + const esmSchemaKeys = Object.keys(esmModule.schemas).sort(); + + expect(cjsSchemaKeys).to.deep.equal(esmSchemaKeys); + }); + }); + + describe("TypeScript type definitions", function () { + it("should have type definition file for main export", function () { + const fs = require("fs"); + const dtsPath = path.join(__dirname, "..", "dist", "index.d.ts"); + expect(fs.existsSync(dtsPath)).to.be.true; + }); + + it("should have type definitions for validate module", function () { + const fs = require("fs"); + const dtsPath = path.join(__dirname, "..", "dist", "validate.d.ts"); + expect(fs.existsSync(dtsPath)).to.be.true; + }); + + it("should have type definitions for files module", function () { + const fs = require("fs"); + const dtsPath = path.join(__dirname, "..", "dist", "files.d.ts"); + expect(fs.existsSync(dtsPath)).to.be.true; + }); + + it("should have type definitions for resolvePaths module", function () { + const fs = require("fs"); + const dtsPath = path.join(__dirname, "..", "dist", "resolvePaths.d.ts"); + expect(fs.existsSync(dtsPath)).to.be.true; + }); + + it("should export ValidateOptions interface in type definitions", function () { + const fs = require("fs"); + const dtsPath = path.join(__dirname, "..", "dist", "validate.d.ts"); + const content = fs.readFileSync(dtsPath, "utf8"); + expect(content).to.include("ValidateOptions"); + }); + + it("should export ValidateResult interface in type definitions", function () { + const fs = require("fs"); + const dtsPath = path.join(__dirname, "..", "dist", "validate.d.ts"); + const content = fs.readFileSync(dtsPath, "utf8"); + expect(content).to.include("ValidateResult"); + }); + }); + + describe("Package exports field verification", function () { + it("should have correct main entry in package.json", function () { + const packageJson = require("../package.json"); + expect(packageJson.main).to.equal("dist/index.js"); + }); + + it("should have correct types entry in package.json", function () { + const packageJson = require("../package.json"); + expect(packageJson.types).to.equal("dist/index.d.ts"); + }); + + it("should have correct exports.require in package.json", function () { + const packageJson = require("../package.json"); + expect(packageJson.exports["."]).to.have.property("require"); + expect(packageJson.exports["."].require).to.equal("./dist/index.js"); + }); + + it("should have correct exports.import in package.json", function () { + const packageJson = require("../package.json"); + expect(packageJson.exports["."]).to.have.property("import"); + expect(packageJson.exports["."].import).to.equal("./dist/index.mjs"); + }); + + it("should have correct exports.types in package.json", function () { + const packageJson = require("../package.json"); + expect(packageJson.exports["."]).to.have.property("types"); + expect(packageJson.exports["."].types).to.equal("./dist/index.d.ts"); + }); + }); + }); +})(); diff --git a/test/resolvePaths.test.js b/test/resolvePaths.test.js index be6c24b6..e30f2b8c 100644 --- a/test/resolvePaths.test.js +++ b/test/resolvePaths.test.js @@ -437,6 +437,20 @@ const path = require("path"); expect(error.message).to.equal("Object type is required for nested objects."); } }); + + it("should throw error for invalid objectType", async function () { + const config = { relativePathBase: "file" }; + const object = { + someProp: "value", + }; + + try { + await resolvePaths({ config, object, filePath: mockFilePath, nested: true, objectType: "invalid" }); + expect.fail("Should have thrown an error"); + } catch (error) { + expect(error.message).to.equal("Invalid objectType"); + } + }); }); describe("null and empty object handling", function () {