From 98b5744a328fb448038a0f7cc0632514e612857e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:30:01 +0000 Subject: [PATCH 1/6] Initial plan From e2f132fb31fcd980cd8ef4b36478ec069edeebef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:43:21 +0000 Subject: [PATCH 2/6] Add AST-based test detection for documentation formats - Add AST parser adapters in resolver/src/ast/ directory: - parsers/markdown.js using unified + remark-parse - parsers/html.js using unified + rehype-parse - parsers/asciidoc.js using asciidoctor - parsers/rst.js using restructured - parsers/xml.js using @xmldom/xmldom - index.js exposing parseToAst(content, format) - Add AST node matching engine in resolver/src/ast/matcher.js: - matchNodes(ast, astConfig) returns matched nodes with positions and extracted values - Supports attribute matching: exact string, regex, any-of, exists-check - Supports extract mapping for capture groups - Add caching for parsed ASTs in resolver/src/ast/cache.js - Extend markupDefinition schema in common/src/schemas/src_schemas/config_v3.schema.json: - Add ast property as astNodeMatch object - Add validation requiring at least one of ast or regex - Modify markup processing in utils.js parseContent() function: - Add AST-based matching before regex patterns - Handle AST-only and AST+regex (AND) modes - Add dependencies to resolver/package.json: - unified, remark-parse, rehype-parse, asciidoctor, restructured, @xmldom/xmldom - Add tests for AST-based detection Co-authored-by: hawkeyexl <5209367+hawkeyexl@users.noreply.github.com> --- .../schemas/src_schemas/config_v3.schema.json | 126 + resolver/package-lock.json | 3773 +++++++++++++++-- resolver/package.json | 8 +- resolver/src/ast/cache.js | 91 + resolver/src/ast/index.js | 83 + resolver/src/ast/matcher.js | 278 ++ resolver/src/ast/parsers/asciidoc.js | 91 + resolver/src/ast/parsers/html.js | 25 + resolver/src/ast/parsers/markdown.js | 25 + resolver/src/ast/parsers/rst.js | 22 + resolver/src/ast/parsers/xml.js | 146 + resolver/src/index.test.js | 221 + resolver/src/utils.js | 156 +- 13 files changed, 4726 insertions(+), 319 deletions(-) create mode 100644 resolver/src/ast/cache.js create mode 100644 resolver/src/ast/index.js create mode 100644 resolver/src/ast/matcher.js create mode 100644 resolver/src/ast/parsers/asciidoc.js create mode 100644 resolver/src/ast/parsers/html.js create mode 100644 resolver/src/ast/parsers/markdown.js create mode 100644 resolver/src/ast/parsers/rst.js create mode 100644 resolver/src/ast/parsers/xml.js diff --git a/common/src/schemas/src_schemas/config_v3.schema.json b/common/src/schemas/src_schemas/config_v3.schema.json index 6eb2430..e1ddd09 100644 --- a/common/src/schemas/src_schemas/config_v3.schema.json +++ b/common/src/schemas/src_schemas/config_v3.schema.json @@ -301,11 +301,19 @@ }, "markupDefinition": { "type": "object", + "anyOf": [ + { "required": ["ast"] }, + { "required": ["regex"] } + ], "properties": { "name": { "description": "Name of the markup definition", "type": "string" }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "$ref": "#/components/schemas/astNodeMatch" + }, "regex": { "description": "Regular expressions to match the markup type.", "anyOf": [ @@ -343,6 +351,62 @@ }, "title": "Markup definition" }, + "astNodeMatch": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { "type": "string" }, + { + "type": "array", + "items": { "type": "string" } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { "type": "string" }, + { "type": "boolean" }, + { + "type": "array", + "items": { "type": "string" } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { "type": "string" }, + { "type": "boolean" } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "$ref": "#/components/schemas/astNodeMatch" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { "$1": "attributes.lang", "$2": "value" }, + { "$1": "content" } + ] + } + }, + "title": "AST node match configuration" + }, "markupActionString": { "type": "string", "enum": [ @@ -523,6 +587,68 @@ }, { "crawl": true + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": ["md"], + "markup": [ + { + "name": "bashCodeBlock", + "ast": { + "nodeType": "code", + "attributes": { + "lang": ["bash", "sh"] + }, + "extract": { + "$1": "attributes.lang", + "$2": "value" + } + }, + "actions": [ + { + "runCode": { + "language": "$1", + "code": "$2" + } + } + ] + } + ] + } + ] + }, + { + "fileTypes": [ + { + "extends": "dita", + "extensions": ["dita", "xml"], + "markup": [ + { + "name": "ditaCodeblock", + "ast": { + "nodeType": "element", + "attributes": { + "tagName": "codeblock", + "outputclass": ["bash", "shell"] + }, + "extract": { + "$1": "attributes.outputclass", + "$2": "content" + } + }, + "actions": [ + { + "runShell": { + "command": "$2" + } + } + ] + } + ] + } + ] } ] } diff --git a/resolver/package-lock.json b/resolver/package-lock.json index b7120d1..21a85b7 100644 --- a/resolver/package-lock.json +++ b/resolver/package-lock.json @@ -10,12 +10,18 @@ "license": "AGPL-3.0-only", "dependencies": { "@apidevtools/json-schema-ref-parser": "^15.1.3", + "@xmldom/xmldom": "^0.9.6", "ajv": "^8.17.1", + "asciidoctor": "^3.0.4", "axios": "^1.13.2", "doc-detective-common": "^3.6.0", "dotenv": "^17.2.3", "json-schema-faker": "^0.5.9", - "posthog-node": "^5.15.0" + "posthog-node": "^5.15.0", + "rehype-parse": "^9.0.1", + "remark-parse": "^11.0.0", + "restructured": "^0.0.11", + "unified": "^11.0.5" }, "devDependencies": { "body-parser": "^2.2.1", @@ -43,6 +49,201 @@ "@types/json-schema": "^7.0.15" } }, + "node_modules/@asciidoctor/cli": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@asciidoctor/cli/-/cli-4.0.0.tgz", + "integrity": "sha512-x2T9gW42921Zd90juEagtbViPZHNP2MWf0+6rJEkOzW7E9m3TGJtz+Guye9J0gwrpZsTMGCpfYMQy1We3X7osg==", + "license": "MIT", + "dependencies": { + "yargs": "17.3.1" + }, + "bin": { + "asciidoctor": "bin/asciidoctor", + "asciidoctorjs": "bin/asciidoctor" + }, + "engines": { + "node": ">=16", + "npm": ">=8.0.0" + }, + "peerDependencies": { + "@asciidoctor/core": ">=2 <4" + } + }, + "node_modules/@asciidoctor/cli/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@asciidoctor/cli/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@asciidoctor/cli/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/@asciidoctor/cli/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@asciidoctor/cli/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@asciidoctor/cli/node_modules/yargs": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@asciidoctor/core": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-3.0.4.tgz", + "integrity": "sha512-41SDMi7iRRBViPe0L6VWFTe55bv6HEOJeRqMj5+E5wB1YPdUPuTucL4UAESPZM6OWmn4t/5qM5LusXomFUVwVQ==", + "license": "MIT", + "dependencies": { + "@asciidoctor/opal-runtime": "3.0.1", + "unxhr": "1.2.0" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, + "node_modules/@asciidoctor/opal-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@asciidoctor/opal-runtime/-/opal-runtime-3.0.1.tgz", + "integrity": "sha512-iW7ACahOG0zZft4A/4CqDcc7JX+fWRNjV5tFAVkNCzwZD+EnFolPaUOPYt8jzadc0+Bgd80cQTtRMQnaaV1kkg==", + "license": "MIT", + "dependencies": { + "glob": "8.1.0", + "unxhr": "1.2.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@asciidoctor/opal-runtime/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@asciidoctor/opal-runtime/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -174,12 +375,66 @@ "node": ">=4" } }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "peer": true }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz", + "integrity": "sha512-p96FSY54r+WJ50FIOsCOjyj/wavs8921hG5+kVMmZgKcvIKxMXHTrjNJvRgWa/zuX3B6t2lijLNFaOyuxUH+2A==", + "license": "MIT", + "engines": { + "node": ">=14.6" + } + }, + "node_modules/a-sync-waterfall": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", + "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", + "license": "MIT" + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -217,6 +472,24 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-es7-plugin": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/acorn-es7-plugin/-/acorn-es7-plugin-1.1.7.tgz", + "integrity": "sha512-7D+8kscFMf6F2t+8ZRYmv82CncDZETsaZ4dEl5lh3qQez7FVABk2Vz616SAbnIq1PbNsLVaZjl2oSkk5BWAKng==", + "license": "MIT" + }, "node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -287,7 +560,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -298,103 +570,350 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/balanced-match": { + "node_modules/array-buffer-byte-length": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", - "dev": true, + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "license": "MIT", "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, + "node_modules/array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha512-Ene1hbrinPZ1qPoZp7NSx4jQnh4nr7MtY78pHNb+yr8yHbxmTS7ChGW0a55JKA7TkRDeoQxK4GcJaCvBYplSKA==", + "license": "MIT" + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, + "node_modules/asciidoctor": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/asciidoctor/-/asciidoctor-3.0.4.tgz", + "integrity": "sha512-hIc0Bx73wePxtic+vWBHOIgMfKSNiCmRz7BBfkyykXATrw20YGd5a3CozCHvqEPH+Wxp5qKD4aBsgtokez8nEA==", "license": "MIT", + "dependencies": { + "@asciidoctor/cli": "4.0.0", + "@asciidoctor/core": "3.0.4", + "ejs": "^3.1.2", + "handlebars": "^4.7.6", + "nunjucks": "^3.2.1", + "pug": "^3.0.0" + }, + "bin": { + "asciidoctor": "bin/asciidoctor", + "asciidoctorjs": "bin/asciidoctor" + }, "engines": { - "node": ">= 0.8" + "node": ">=16", + "npm": ">=8" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "node_modules/asciidoctor/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">= 0.4" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/call-bound": { - "version": "1.0.4", + "node_modules/asciidoctor/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/asciidoctor/node_modules/nunjucks": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", + "license": "BSD-2-Clause", + "dependencies": { + "a-sync-waterfall": "^1.0.0", + "asap": "^2.0.3", + "commander": "^5.1.0" + }, + "bin": { + "nunjucks-precompile": "bin/precompile" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "chokidar": "^3.3.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/assert-never": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "license": "MIT" + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -413,6 +932,15 @@ "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", "license": "MIT" }, + "node_modules/call-signature": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/call-signature/-/call-signature-0.0.2.tgz", + "integrity": "sha512-qvYvkAVcoae0obt8OsZn0VEBHeEpvYIZDy1gGYtZDJG0fHawew+Mi0dBjieFz8F8dzQ2Kr19+nsDm+T5XFVs+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -463,6 +991,25 @@ "node": ">=8" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "license": "MIT", + "dependencies": { + "is-regex": "^1.0.3" + } + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -552,7 +1099,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -563,8 +1109,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -578,6 +1123,32 @@ "node": ">= 0.8" } }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, "node_modules/content-disposition": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", @@ -621,6 +1192,14 @@ "node": ">=6.6.0" } }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -654,11 +1233,61 @@ "node": ">= 8" } }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -672,25 +1301,94 @@ } } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", "license": "MIT", - "engines": { - "node": ">=0.4.0" + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/diff": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", @@ -701,6 +1399,12 @@ "node": ">=0.3.1" } }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "license": "Apache-2.0" + }, "node_modules/doc-detective-common": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/doc-detective-common/-/doc-detective-common-3.6.0.tgz", @@ -716,6 +1420,12 @@ "yaml": "^2.8.2" } }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "license": "MIT" + }, "node_modules/dotenv": { "version": "17.2.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", @@ -745,8 +1455,7 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/ee-first": { "version": "1.1.1", @@ -755,12 +1464,47 @@ "dev": true, "license": "MIT" }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "node_modules/empower": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/empower/-/empower-1.3.1.tgz", + "integrity": "sha512-uB6/ViBaawOO/uujFADTK3SqdYlxYNn+N4usK9MRKZ4Hbn/1QSy8k2PezxCA2/+JGbF8vd/eOfghZ90oOSDZCA==", + "license": "MIT", + "dependencies": { + "core-js": "^2.0.0", + "empower-core": "^1.2.0" + } + }, + "node_modules/empower-core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/empower-core/-/empower-core-1.2.0.tgz", + "integrity": "sha512-g6+K6Geyc1o6FdXs9HwrXleCFan7d66G5xSCfSF7x1mJDCes6t0om9lFQG3zOrzh3Bkb/45N0cZ5Gqsf7YrzGQ==", + "license": "MIT", + "dependencies": { + "call-signature": "0.0.2", + "core-js": "^2.0.0" + } + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -771,6 +1515,86 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -816,11 +1640,27 @@ "node": ">= 0.4" } }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -845,6 +1685,24 @@ "node": ">=4" } }, + "node_modules/espurify": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/espurify/-/espurify-1.8.1.tgz", + "integrity": "sha512-ZDko6eY/o+D/gHCWyHTU85mKDgYcS4FJj7S+YD6WIInm7GQ6AnOjmcL4+buFV/JOztVLELi/7MmuGU5NHta0Mg==", + "license": "MIT", + "dependencies": { + "core-js": "^2.0.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -932,6 +1790,12 @@ "node": ">= 0.6" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -942,6 +1806,27 @@ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fill-keys": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", @@ -966,6 +1851,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", @@ -1028,6 +1927,21 @@ } } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -1076,6 +1990,27 @@ "node": ">= 0.6" } }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1084,11 +2019,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -1130,6 +2102,23 @@ "node": ">= 0.4" } }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -1151,6 +2140,36 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -1163,6 +2182,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1172,25 +2224,25 @@ "node": ">=8" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "license": "MIT", "dependencies": { - "has-symbols": "^1.0.3" + "dunder-proto": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -1199,10 +2251,37 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -1210,6 +2289,74 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -1257,11 +2404,40 @@ "url": "https://opencollective.com/express" } }, + "node_modules/indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/ipaddr.js": { "version": "1.9.1", @@ -1273,14 +2449,15 @@ "node": ">= 0.10" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -1289,154 +2466,574 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jackspeak": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", - "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "hasown": "^2.0.2" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jsep": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", - "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, "engines": { - "node": ">= 10.16.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/json-schema-faker": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/json-schema-faker/-/json-schema-faker-0.5.9.tgz", - "integrity": "sha512-fNKLHgDvfGNNTX1zqIjqFMJjCLzJ2kvnJ831x4aqkAoeE4jE2TxvpJdhOnk3JU3s42vFzmXvkpbYzH5H3ncAzg==", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "license": "MIT", "dependencies": { - "json-schema-ref-parser": "^6.1.0", - "jsonpath-plus": "^10.3.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, - "bin": { - "jsf": "bin/gen.cjs" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/json-schema-ref-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz", - "integrity": "sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw==", - "deprecated": "Please switch to @apidevtools/json-schema-ref-parser", + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", "license": "MIT", "dependencies": { - "call-me-maybe": "^1.0.1", - "js-yaml": "^3.12.1", - "ono": "^4.0.11" + "acorn": "^7.1.1", + "object-assign": "^4.1.1" } }, - "node_modules/json-schema-ref-parser/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/json-schema-ref-parser/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "call-bound": "^1.0.3" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } }, - "node_modules/jsonpath-plus": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", - "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "license": "MIT", "dependencies": { - "@jsep-plugin/assignment": "^1.3.0", - "@jsep-plugin/regex": "^1.0.4", - "jsep": "^1.4.0" + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/jackspeak": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/json-schema-faker": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/json-schema-faker/-/json-schema-faker-0.5.9.tgz", + "integrity": "sha512-fNKLHgDvfGNNTX1zqIjqFMJjCLzJ2kvnJ831x4aqkAoeE4jE2TxvpJdhOnk3JU3s42vFzmXvkpbYzH5H3ncAzg==", + "license": "MIT", + "dependencies": { + "json-schema-ref-parser": "^6.1.0", + "jsonpath-plus": "^10.3.0" + }, + "bin": { + "jsf": "bin/gen.cjs" + } + }, + "node_modules/json-schema-ref-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz", + "integrity": "sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw==", + "deprecated": "Please switch to @apidevtools/json-schema-ref-parser", + "license": "MIT", + "dependencies": { + "call-me-maybe": "^1.0.1", + "js-yaml": "^3.12.1", + "ono": "^4.0.11" + } + }, + "node_modules/json-schema-ref-parser/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/json-schema-ref-parser/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/jsonpath-plus": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", + "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" }, "bin": { "jsonpath": "bin/jsonpath-cli.js", @@ -1446,6 +3043,22 @@ "node": ">=18.0.0" } }, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "license": "MIT", + "dependencies": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "node_modules/jstransformer/node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "license": "MIT" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1461,68 +3074,553 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", - "dev": true, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", + "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", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "micromark-util-types": "^2.0.0" } }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "dev": true, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "dev": true, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -1560,6 +3658,15 @@ "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==", + "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", @@ -1628,8 +3735,7 @@ "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/negotiator": { "version": "1.0.0", @@ -1641,11 +3747,36 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -1654,6 +3785,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -1671,7 +3831,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -1685,6 +3844,23 @@ "format-util": "^1.0.3" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -1721,6 +3897,18 @@ "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", "dev": true }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1752,7 +3940,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, "license": "MIT" }, "node_modules/path-scurry": { @@ -1777,27 +3964,200 @@ "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=16" + "engines": { + "node": ">=16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/posthog-node": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.15.0.tgz", + "integrity": "sha512-Q70DGmUoy/Lavrq+qn2shIj/EQSeyaz6huIZQlLE6y8Xa6xtZw+Jg1lyr2nC1sEEFPCU1X7zkNvP6mjbYwqjYA==", + "license": "MIT", + "dependencies": { + "@posthog/core": "1.6.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/power-assert": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/power-assert/-/power-assert-1.6.1.tgz", + "integrity": "sha512-VWkkZV6Y+W8qLX/PtJu2Ur2jDPIs0a5vbP0TpKeybNcIXmT4vcKoVkyTp5lnQvTpY/DxacAZ4RZisHRHLJcAZQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.2", + "empower": "^1.3.1", + "power-assert-formatter": "^1.4.1", + "universal-deep-strict-equal": "^1.2.1", + "xtend": "^4.0.0" + } + }, + "node_modules/power-assert-context-formatter": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/power-assert-context-formatter/-/power-assert-context-formatter-1.2.0.tgz", + "integrity": "sha512-HLNEW8Bin+BFCpk/zbyKwkEu9W8/zThIStxGo7weYcFkKgMuGCHUJhvJeBGXDZf0Qm2xis4pbnnciGZiX0EpSg==", + "license": "MIT", + "dependencies": { + "core-js": "^2.0.0", + "power-assert-context-traversal": "^1.2.0" + } + }, + "node_modules/power-assert-context-reducer-ast": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/power-assert-context-reducer-ast/-/power-assert-context-reducer-ast-1.2.0.tgz", + "integrity": "sha512-EgOxmZ/Lb7tw4EwSKX7ZnfC0P/qRZFEG28dx/690qvhmOJ6hgThYFm5TUWANDLK5NiNKlPBi5WekVGd2+5wPrw==", + "license": "MIT", + "dependencies": { + "acorn": "^5.0.0", + "acorn-es7-plugin": "^1.0.12", + "core-js": "^2.0.0", + "espurify": "^1.6.0", + "estraverse": "^4.2.0" + } + }, + "node_modules/power-assert-context-reducer-ast/node_modules/acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/power-assert-context-traversal": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/power-assert-context-traversal/-/power-assert-context-traversal-1.2.0.tgz", + "integrity": "sha512-NFoHU6g2umNajiP2l4qb0BRWD773Aw9uWdWYH9EQsVwIZnog5bd2YYLFCVvaxWpwNzWeEfZIon2xtyc63026pQ==", + "license": "MIT", + "dependencies": { + "core-js": "^2.0.0", + "estraverse": "^4.1.0" + } + }, + "node_modules/power-assert-formatter": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/power-assert-formatter/-/power-assert-formatter-1.4.1.tgz", + "integrity": "sha512-c2QzTk1a6BUumuzjffFUrsMlx2gqLEoeEMrx6gVaHzQ/zTBTibQGblaQslbv72eq9RJNFQXRryjTHoffIEz+ww==", + "license": "MIT", + "dependencies": { + "core-js": "^2.0.0", + "power-assert-context-formatter": "^1.0.7", + "power-assert-context-reducer-ast": "^1.0.7", + "power-assert-renderer-assertion": "^1.0.7", + "power-assert-renderer-comparison": "^1.0.7", + "power-assert-renderer-diagram": "^1.0.7", + "power-assert-renderer-file": "^1.0.7" + } + }, + "node_modules/power-assert-renderer-assertion": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/power-assert-renderer-assertion/-/power-assert-renderer-assertion-1.2.0.tgz", + "integrity": "sha512-3F7Q1ZLmV2ZCQv7aV7NJLNK9G7QsostrhOU7U0RhEQS/0vhEqrRg2jEJl1jtUL4ZyL2dXUlaaqrmPv5r9kRvIg==", + "license": "MIT", + "dependencies": { + "power-assert-renderer-base": "^1.1.1", + "power-assert-util-string-width": "^1.2.0" + } + }, + "node_modules/power-assert-renderer-base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/power-assert-renderer-base/-/power-assert-renderer-base-1.1.1.tgz", + "integrity": "sha512-aGCUi0NuNd/fVS6KKMLTjRP58cdlHlQKgXV4WKl3YlUhnN0d9QBEYOyvmiumdjk+5GuZmozvEmBIcTAcxEZqnw==", + "license": "MIT" + }, + "node_modules/power-assert-renderer-comparison": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/power-assert-renderer-comparison/-/power-assert-renderer-comparison-1.2.0.tgz", + "integrity": "sha512-7c3RKPDBKK4E3JqdPtYRE9cM8AyX4LC4yfTvvTYyx8zSqmT5kJnXwzR0yWQLOavACllZfwrAGQzFiXPc5sWa+g==", + "license": "MIT", + "dependencies": { + "core-js": "^2.0.0", + "diff-match-patch": "^1.0.0", + "power-assert-renderer-base": "^1.1.1", + "stringifier": "^1.3.0", + "type-name": "^2.0.1" + } + }, + "node_modules/power-assert-renderer-diagram": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/power-assert-renderer-diagram/-/power-assert-renderer-diagram-1.2.0.tgz", + "integrity": "sha512-JZ6PC+DJPQqfU6dwSmpcoD7gNnb/5U77bU5KgNwPPa+i1Pxiz6UuDeM3EUBlhZ1HvH9tMjI60anqVyi5l2oNdg==", + "license": "MIT", + "dependencies": { + "core-js": "^2.0.0", + "power-assert-renderer-base": "^1.1.1", + "power-assert-util-string-width": "^1.2.0", + "stringifier": "^1.3.0" + } + }, + "node_modules/power-assert-renderer-file": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/power-assert-renderer-file/-/power-assert-renderer-file-1.2.0.tgz", + "integrity": "sha512-/oaVrRbeOtGoyyd7e4IdLP/jIIUFJdqJtsYzP9/88R39CMnfF/S/rUc8ZQalENfUfQ/wQHu+XZYRMaCEZmEesg==", + "license": "MIT", + "dependencies": { + "power-assert-renderer-base": "^1.1.1" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" + "node_modules/power-assert-util-string-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/power-assert-util-string-width/-/power-assert-util-string-width-1.2.0.tgz", + "integrity": "sha512-lX90G0igAW0iyORTILZ/QjZWsa1MZ6VVY3L0K86e2eKun3S4LKPH4xZIl8fdeMYLfOjkaszbNSzf1uugLeAm2A==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0" + } }, - "node_modules/posthog-node": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.15.0.tgz", - "integrity": "sha512-Q70DGmUoy/Lavrq+qn2shIj/EQSeyaz6huIZQlLE6y8Xa6xtZw+Jg1lyr2nC1sEEFPCU1X7zkNvP6mjbYwqjYA==", + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "license": "MIT", "dependencies": { - "@posthog/core": "1.6.0" - }, - "engines": { - "node": ">=20" + "asap": "~2.0.3" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/proxy-addr": { @@ -1831,6 +4191,130 @@ "resolve": "^1.11.1" } }, + "node_modules/pug": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", + "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", + "license": "MIT", + "dependencies": { + "pug-code-gen": "^3.0.3", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "node_modules/pug-code-gen": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz", + "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==", + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.1.0", + "pug-runtime": "^3.0.1", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "node_modules/pug-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", + "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", + "license": "MIT" + }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "license": "MIT", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "license": "MIT" + }, + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "license": "MIT" + }, "node_modules/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", @@ -1882,11 +4366,97 @@ "node": ">= 0.10" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rehype-parse": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -1903,7 +4473,6 @@ "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", @@ -1920,6 +4489,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/restructured": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/restructured/-/restructured-0.0.11.tgz", + "integrity": "sha512-KqEuVvRfyDcU6bsueovH4QQFiSj72SHRa01Rn1AwEgpYTshVt26Q8aLQUeAg376phU0jkhDxvUeKiQxY2DNYXw==", + "license": "MIT", + "dependencies": { + "commander": "^2.9.0", + "lodash": "^4.0.0", + "power-assert": "^1.2.0", + "unist-util-map": "^1.0.2" + }, + "bin": { + "restructured": "bin/restructured.js" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -1937,6 +4521,25 @@ "node": ">= 18" } }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1957,6 +4560,39 @@ } ] }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2058,6 +4694,52 @@ "node": ">= 18" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -2088,7 +4770,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2108,7 +4789,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2125,7 +4805,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -2144,7 +4823,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -2203,6 +4881,25 @@ "node": ">=8" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -2219,6 +4916,19 @@ "node": ">= 0.8" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -2272,10 +4982,77 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringifier": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stringifier/-/stringifier-1.4.1.tgz", + "integrity": "sha512-7TGia2tzGIfw+Nki9r6kVxdP0vWeQ7oVZtyMnGxWsAJYe0XYV6VSGrfzUXm7r+icYfvpFlGNrwB+PYwFg+hfag==", + "license": "MIT", + "dependencies": { + "core-js": "^2.0.0", + "traverse": "^0.6.6", + "type-name": "^2.0.1" } }, "node_modules/strip-ansi": { @@ -2346,7 +5123,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2355,6 +5131,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -2365,6 +5155,39 @@ "node": ">=0.6" } }, + "node_modules/token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "license": "MIT" + }, + "node_modules/traverse": { + "version": "0.6.11", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.11.tgz", + "integrity": "sha512-vxXDZg8/+p3gblxB6BhhG5yWVn1kGRlaL8O78UDXc3wRnPizB5g83dcvWV1jpDMIPnjZjOFuxlMmE82XJ4407w==", + "license": "MIT", + "dependencies": { + "gopd": "^1.2.0", + "typedarray.prototype.slice": "^1.0.5", + "which-typed-array": "^1.1.18" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -2413,6 +5236,191 @@ "node": ">= 0.6" } }, + "node_modules/type-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/type-name/-/type-name-2.0.2.tgz", + "integrity": "sha512-kkgkuqR/jKdKO5oh/I2SMu2dGbLXoJq0zkdgbxaqYK+hr9S9edwVVGf+tMUFTx2gH9TN2+Zu9JZ/Njonb3cjhA==", + "license": "MIT" + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray.prototype.slice": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.5.tgz", + "integrity": "sha512-q7QNVDGTdl702bVFiI5eY4l/HkgCM6at9KhcFbgUAzezHFbOVy4+0O/lCjsABEQwbZPravVfBIiBVGo89yzHFg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "math-intrinsics": "^1.1.0", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-offset": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-map": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unist-util-map/-/unist-util-map-1.0.5.tgz", + "integrity": "sha512-dFil/AN6vqhnQWNCZk0GF/G3+Q5YwsB+PqjnzvpO2wzdRtUJ1E8PN+XRE/PRr/G3FzKjRTJU0haqE0Ekl+O3Ag==", + "license": "MIT", + "dependencies": { + "object-assign": "^4.0.1" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universal-deep-strict-equal": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/universal-deep-strict-equal/-/universal-deep-strict-equal-1.2.2.tgz", + "integrity": "sha512-UpnFi3/IF3jZHIHTdQXTHLCqpBP3805OFFRPHgvCS7k0oob2YVXxMTjS0U0g9qJTzqFRMwEnFFSlFLqt6zwjTQ==", + "license": "MIT", + "dependencies": { + "array-filter": "^1.0.0", + "indexof": "0.0.1", + "object-keys": "^1.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2423,6 +5431,15 @@ "node": ">= 0.8" } }, + "node_modules/unxhr": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.2.0.tgz", + "integrity": "sha512-6cGpm8NFXPD9QbSNx0cD2giy7teZ6xOkCUH3U89WKVkL9N9rBrWjlCwhR94Re18ZlAop4MOc3WU1M3Hv/bgpIw==", + "license": "MIT", + "engines": { + "node": ">=8.11" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2433,6 +5450,173 @@ "node": ">= 0.8" } }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, "node_modules/workerpool": { "version": "9.3.2", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.2.tgz", @@ -2444,7 +5628,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2520,7 +5703,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2528,14 +5710,12 @@ "node_modules/wrap-ansi/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/wrap-ansi/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2549,7 +5729,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2560,14 +5739,21 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -2609,7 +5795,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "engines": { "node": ">=12" } diff --git a/resolver/package.json b/resolver/package.json index 8e6fb29..d79b301 100644 --- a/resolver/package.json +++ b/resolver/package.json @@ -25,12 +25,18 @@ "homepage": "https://github.com/doc-detective/doc-detective-core#readme", "dependencies": { "@apidevtools/json-schema-ref-parser": "^15.1.3", + "@xmldom/xmldom": "^0.9.6", "ajv": "^8.17.1", + "asciidoctor": "^3.0.4", "axios": "^1.13.2", "doc-detective-common": "^3.6.0", "dotenv": "^17.2.3", "json-schema-faker": "^0.5.9", - "posthog-node": "^5.15.0" + "posthog-node": "^5.15.0", + "rehype-parse": "^9.0.1", + "remark-parse": "^11.0.0", + "restructured": "^0.0.11", + "unified": "^11.0.5" }, "devDependencies": { "body-parser": "^2.2.1", diff --git a/resolver/src/ast/cache.js b/resolver/src/ast/cache.js new file mode 100644 index 0000000..132ebc7 --- /dev/null +++ b/resolver/src/ast/cache.js @@ -0,0 +1,91 @@ +/** + * AST cache module for Doc Detective. + * Caches parsed ASTs by file path and content hash to avoid redundant parsing. + */ + +const crypto = require("crypto"); +const { parseToAst } = require("./index"); + +/** + * In-memory cache for parsed ASTs. + * Key: filePath, Value: { hash: string, ast: Object } + */ +const cache = new Map(); + +/** + * Computes a hash of the content for cache invalidation. + * + * @param {string} content - The content to hash. + * @returns {string} The MD5 hash of the content. + */ +function computeHash(content) { + return crypto.createHash("md5").update(content).digest("hex"); +} + +/** + * Gets a cached AST or parses and caches the content. + * + * @param {string} content - The content to parse. + * @param {string} format - The format of the content. + * @param {string} filePath - The file path for caching purposes. + * @returns {Object|null} The parsed AST, or null if parsing fails. + */ +function getOrParse(content, format, filePath) { + if (!content || !format) { + return null; + } + + const hash = computeHash(content); + + // Check cache + if (filePath && cache.has(filePath)) { + const cached = cache.get(filePath); + if (cached.hash === hash) { + return cached.ast; + } + // Content changed, invalidate cache + cache.delete(filePath); + } + + // Parse content + const ast = parseToAst(content, format); + + // Cache result if we have a file path + if (filePath && ast) { + cache.set(filePath, { hash, ast }); + } + + return ast; +} + +/** + * Clears the entire AST cache. + */ +function clearCache() { + cache.clear(); +} + +/** + * Removes a specific entry from the cache. + * + * @param {string} filePath - The file path to remove from cache. + */ +function invalidate(filePath) { + cache.delete(filePath); +} + +/** + * Gets the current size of the cache. + * + * @returns {number} The number of entries in the cache. + */ +function size() { + return cache.size; +} + +module.exports = { + getOrParse, + clearCache, + invalidate, + size, +}; diff --git a/resolver/src/ast/index.js b/resolver/src/ast/index.js new file mode 100644 index 0000000..ebe782f --- /dev/null +++ b/resolver/src/ast/index.js @@ -0,0 +1,83 @@ +/** + * AST parsing module for Doc Detective. + * Provides unified interface for parsing various document formats into ASTs. + */ + +const markdownParser = require("./parsers/markdown"); +const htmlParser = require("./parsers/html"); +const asciidocParser = require("./parsers/asciidoc"); +const rstParser = require("./parsers/rst"); +const xmlParser = require("./parsers/xml"); + +/** + * Map of format names to their respective parsers. + */ +const parsers = { + markdown: markdownParser, + md: markdownParser, + mdx: markdownParser, + html: htmlParser, + htm: htmlParser, + asciidoc: asciidocParser, + adoc: asciidocParser, + asc: asciidocParser, + rst: rstParser, + restructuredtext: rstParser, + xml: xmlParser, + dita: xmlParser, + ditamap: xmlParser, +}; + +/** + * Parses content into an AST based on the specified format. + * + * @param {string} content - The content to parse. + * @param {string} format - The format of the content (e.g., 'markdown', 'html', 'dita'). + * @returns {Object|null} The parsed AST, or null if parsing fails or format is unsupported. + */ +function parseToAst(content, format) { + if (!content || typeof content !== "string") { + return null; + } + + const formatLower = (format || "").toLowerCase(); + const parser = parsers[formatLower]; + + if (!parser) { + return null; + } + + try { + return parser.parse(content); + } catch (error) { + return null; + } +} + +/** + * Gets the parser for a given file extension. + * + * @param {string} extension - The file extension (without leading dot). + * @returns {Object|null} The parser module, or null if unsupported. + */ +function getParserForExtension(extension) { + const extLower = (extension || "").toLowerCase().replace(/^\./, ""); + return parsers[extLower] || null; +} + +/** + * Checks if a format is supported for AST parsing. + * + * @param {string} format - The format to check. + * @returns {boolean} True if the format is supported. + */ +function isFormatSupported(format) { + const formatLower = (format || "").toLowerCase(); + return formatLower in parsers; +} + +module.exports = { + parseToAst, + getParserForExtension, + isFormatSupported, +}; diff --git a/resolver/src/ast/matcher.js b/resolver/src/ast/matcher.js new file mode 100644 index 0000000..899834c --- /dev/null +++ b/resolver/src/ast/matcher.js @@ -0,0 +1,278 @@ +/** + * AST node matching engine for Doc Detective. + * Provides functions to match nodes in an AST based on configuration. + */ + +/** + * Checks if a value matches a pattern. + * Supports: exact string, regex (string starting with /), array (any-of), boolean (exists-check). + * + * @param {*} value - The value to check. + * @param {*} pattern - The pattern to match against. + * @returns {boolean} True if the value matches the pattern. + */ +function matchesPattern(value, pattern) { + // Boolean: exists-check + if (pattern === true) { + return value !== undefined && value !== null; + } + if (pattern === false) { + return value === undefined || value === null; + } + + // Array: any-of matching + if (Array.isArray(pattern)) { + return pattern.some(p => matchesPattern(value, p)); + } + + // Regex pattern (string starting and ending with /) + if (typeof pattern === "string" && pattern.startsWith("/") && pattern.endsWith("/")) { + const regexStr = pattern.slice(1, -1); + try { + const regex = new RegExp(regexStr); + return regex.test(String(value || "")); + } catch (e) { + return false; + } + } + + // Regex pattern with flags (e.g., /pattern/i) + if (typeof pattern === "string" && pattern.startsWith("/")) { + const lastSlash = pattern.lastIndexOf("/"); + if (lastSlash > 0) { + const regexStr = pattern.slice(1, lastSlash); + const flags = pattern.slice(lastSlash + 1); + try { + const regex = new RegExp(regexStr, flags); + return regex.test(String(value || "")); + } catch (e) { + return false; + } + } + } + + // Exact match + return value === pattern; +} + +/** + * Gets a nested value from an object using a dot-separated path. + * + * @param {Object} obj - The object to extract from. + * @param {string} path - The dot-separated path (e.g., "attributes.lang"). + * @returns {*} The value at the path, or undefined if not found. + */ +function getValueByPath(obj, path) { + if (!obj || !path) return undefined; + + const parts = path.split("."); + let current = obj; + + for (const part of parts) { + if (current === null || current === undefined) { + return undefined; + } + current = current[part]; + } + + return current; +} + +/** + * Checks if a node matches the AST configuration. + * + * @param {Object} node - The AST node to check. + * @param {Object} astConfig - The AST matching configuration. + * @returns {boolean} True if the node matches. + */ +function nodeMatches(node, astConfig) { + if (!node || !astConfig) return false; + + // Check nodeType + if (astConfig.nodeType) { + const nodeType = node.type || node.tagName; + if (!matchesPattern(nodeType, astConfig.nodeType)) { + return false; + } + } + + // Check attributes + if (astConfig.attributes) { + for (const [attrName, attrPattern] of Object.entries(astConfig.attributes)) { + // Handle special attribute names + let value; + if (attrName === "tagName") { + value = node.tagName || node.name; + } else if (attrName === "lang" || attrName === "language") { + // For code blocks, check both lang and language + value = node.lang || node.language || + (node.attributes && (node.attributes.lang || node.attributes.language)); + } else if (attrName === "className" || attrName === "class") { + value = node.className || (node.attributes && (node.attributes.className || node.attributes.class)); + } else { + // Check in attributes object first, then directly on node + value = (node.attributes && node.attributes[attrName]) || node[attrName]; + } + + if (!matchesPattern(value, attrPattern)) { + return false; + } + } + } + + // Check content + if (astConfig.content !== undefined) { + const nodeContent = node.value || node.content || node.text || ""; + if (!matchesPattern(nodeContent, astConfig.content)) { + return false; + } + } + + // Check children (all child matchers must match at least one child) + if (astConfig.children && Array.isArray(astConfig.children)) { + const nodeChildren = node.children || []; + for (const childMatcher of astConfig.children) { + const hasMatchingChild = nodeChildren.some(child => nodeMatches(child, childMatcher)); + if (!hasMatchingChild) { + return false; + } + } + } + + return true; +} + +/** + * Extracts values from a node based on the extract configuration. + * + * @param {Object} node - The AST node. + * @param {Object} extractConfig - Mapping of variable names to paths (e.g., { "$1": "attributes.lang" }). + * @returns {Object} Object mapping variable names to extracted values. + */ +function extractValues(node, extractConfig) { + if (!node || !extractConfig) return {}; + + const extracted = {}; + for (const [varName, path] of Object.entries(extractConfig)) { + // Handle special paths + let value; + if (path === "value" || path === "content") { + value = node.value || node.content || node.text || ""; + } else if (path === "tagName" || path === "type") { + value = node.tagName || node.type || node.name || ""; + } else { + value = getValueByPath(node, path); + } + + // Convert the variable name to match expected format ($1 -> 1) + const key = varName.replace(/^\$/, ""); + extracted[key] = value; + } + + return extracted; +} + +/** + * Gets the position of a node in the source content. + * + * @param {Object} node - The AST node. + * @returns {Object|null} Position object with start offset, or null if unavailable. + */ +function getNodePosition(node) { + if (!node) return null; + + // MDAST/HAST position format + if (node.position && typeof node.position.start === "object") { + return { + offset: node.position.start.offset, + line: node.position.start.line, + column: node.position.start.column, + }; + } + + // Direct position properties + if (typeof node.offset === "number") { + return { offset: node.offset }; + } + + // Line-based position + if (typeof node.line === "number") { + return { line: node.line }; + } + + return null; +} + +/** + * Recursively finds all nodes in an AST that match the configuration. + * + * @param {Object} ast - The AST root node. + * @param {Object} astConfig - The AST matching configuration. + * @returns {Array} Array of matching results with node, position, and extracted values. + */ +function matchNodes(ast, astConfig) { + if (!ast || !astConfig) return []; + + const results = []; + + function traverse(node, index = 0) { + if (!node) return; + + // Check if this node matches + if (nodeMatches(node, astConfig)) { + const position = getNodePosition(node); + const extracted = astConfig.extract ? extractValues(node, astConfig.extract) : {}; + + results.push({ + node, + position, + extracted, + sortIndex: position ? (position.offset || position.line * 1000 || index) : index, + }); + } + + // Traverse children + const children = node.children || node.blocks || []; + if (Array.isArray(children)) { + children.forEach((child, childIndex) => traverse(child, childIndex)); + } + } + + traverse(ast); + return results; +} + +/** + * Gets the text content from a matched node. + * + * @param {Object} node - The AST node. + * @returns {string} The text content of the node. + */ +function getNodeContent(node) { + if (!node) return ""; + + // Direct content properties + if (node.value) return node.value; + if (node.content) return node.content; + if (node.text) return node.text; + + // For element nodes, concatenate text children + if (node.children && Array.isArray(node.children)) { + return node.children + .filter(child => child.type === "text" || child.value) + .map(child => child.value || child.text || "") + .join(""); + } + + return ""; +} + +module.exports = { + matchNodes, + nodeMatches, + extractValues, + getNodeContent, + getNodePosition, + matchesPattern, + getValueByPath, +}; diff --git a/resolver/src/ast/parsers/asciidoc.js b/resolver/src/ast/parsers/asciidoc.js new file mode 100644 index 0000000..adf35f4 --- /dev/null +++ b/resolver/src/ast/parsers/asciidoc.js @@ -0,0 +1,91 @@ +/** + * AsciiDoc parser adapter using asciidoctor.js. + * Converts AsciiDoc content to Asciidoctor AST. + */ + +const Asciidoctor = require("asciidoctor"); + +// Create singleton asciidoctor processor +const asciidoctor = Asciidoctor(); + +/** + * Converts Asciidoctor document/block to a normalized AST node. + * @param {Object} node - Asciidoctor node. + * @returns {Object} Normalized AST node. + */ +function normalizeNode(node) { + const normalized = { + type: node.getNodeName ? node.getNodeName() : "unknown", + attributes: {}, + children: [], + content: null, + position: null, + }; + + // Extract attributes + if (node.getAttributes) { + const attrs = node.getAttributes(); + if (attrs && typeof attrs === "object") { + normalized.attributes = { ...attrs }; + } + } + + // Extract specific attributes + if (node.getRole) { + normalized.attributes.role = node.getRole(); + } + if (node.getStyle) { + normalized.attributes.style = node.getStyle(); + } + if (node.getId) { + normalized.attributes.id = node.getId(); + } + + // Extract content based on node type + if (node.getSource) { + normalized.content = node.getSource(); + } else if (node.getContent) { + const content = node.getContent(); + if (typeof content === "string") { + normalized.content = content; + } + } else if (node.getText) { + normalized.content = node.getText(); + } + + // Get source location if available + if (node.getSourceLocation) { + const loc = node.getSourceLocation(); + if (loc) { + normalized.position = { + start: { line: loc.getLineNumber ? loc.getLineNumber() : null }, + }; + } + } + + // Process children + if (node.getBlocks) { + const blocks = node.getBlocks(); + if (blocks && blocks.length > 0) { + normalized.children = blocks.map(normalizeNode); + } + } + + return normalized; +} + +/** + * Parses AsciiDoc content into a normalized AST. + * @param {string} content - The AsciiDoc content to parse. + * @returns {Object|null} The parsed AST, or null if parsing fails. + */ +function parse(content) { + try { + const doc = asciidoctor.load(content, { safe: "safe" }); + return normalizeNode(doc); + } catch (error) { + return null; + } +} + +module.exports = { parse }; diff --git a/resolver/src/ast/parsers/html.js b/resolver/src/ast/parsers/html.js new file mode 100644 index 0000000..93e4c95 --- /dev/null +++ b/resolver/src/ast/parsers/html.js @@ -0,0 +1,25 @@ +/** + * HTML parser adapter using unified + rehype-parse. + * Converts HTML content to HAST (HTML Abstract Syntax Tree). + */ + +const { unified } = require("unified"); +const rehypeParseModule = require("rehype-parse"); +const rehypeParse = rehypeParseModule.default || rehypeParseModule; + +/** + * Parses HTML content into a HAST. + * @param {string} content - The HTML content to parse. + * @returns {Object|null} The parsed HAST, or null if parsing fails. + */ +function parse(content) { + try { + const processor = unified().use(rehypeParse, { fragment: true }); + const ast = processor.parse(content); + return ast; + } catch (error) { + return null; + } +} + +module.exports = { parse }; diff --git a/resolver/src/ast/parsers/markdown.js b/resolver/src/ast/parsers/markdown.js new file mode 100644 index 0000000..7b59101 --- /dev/null +++ b/resolver/src/ast/parsers/markdown.js @@ -0,0 +1,25 @@ +/** + * Markdown parser adapter using unified + remark-parse. + * Converts Markdown content to MDAST (Markdown Abstract Syntax Tree). + */ + +const { unified } = require("unified"); +const remarkParseModule = require("remark-parse"); +const remarkParse = remarkParseModule.default || remarkParseModule; + +/** + * Parses Markdown content into an MDAST. + * @param {string} content - The Markdown content to parse. + * @returns {Object|null} The parsed MDAST, or null if parsing fails. + */ +function parse(content) { + try { + const processor = unified().use(remarkParse); + const ast = processor.parse(content); + return ast; + } catch (error) { + return null; + } +} + +module.exports = { parse }; diff --git a/resolver/src/ast/parsers/rst.js b/resolver/src/ast/parsers/rst.js new file mode 100644 index 0000000..1940ede --- /dev/null +++ b/resolver/src/ast/parsers/rst.js @@ -0,0 +1,22 @@ +/** + * reStructuredText parser adapter using restructured. + * Converts RST content to RST tree. + */ + +const restructured = require("restructured"); + +/** + * Parses RST content into an AST. + * @param {string} content - The RST content to parse. + * @returns {Object|null} The parsed AST, or null if parsing fails. + */ +function parse(content) { + try { + const ast = restructured.parse(content); + return ast; + } catch (error) { + return null; + } +} + +module.exports = { parse }; diff --git a/resolver/src/ast/parsers/xml.js b/resolver/src/ast/parsers/xml.js new file mode 100644 index 0000000..95219dc --- /dev/null +++ b/resolver/src/ast/parsers/xml.js @@ -0,0 +1,146 @@ +/** + * XML/DITA parser adapter using @xmldom/xmldom. + * Converts XML content to a normalized AST-like structure. + */ + +const { DOMParser } = require("@xmldom/xmldom"); + +/** + * Converts array-like object to array. + * @param {Object} nodeList - DOM NodeList or similar. + * @returns {Array} Array of nodes. + */ +function toArray(nodeList) { + if (!nodeList) return []; + const result = []; + for (let i = 0; i < nodeList.length; i++) { + result.push(nodeList[i]); + } + return result; +} + +/** + * Recursively converts DOM node to normalized AST structure. + * @param {Node} node - DOM node. + * @returns {Object|null} Normalized AST node. + */ +function domToAst(node) { + if (!node) return null; + + // Skip text nodes that are only whitespace + if (node.nodeType === 3) { + const text = node.textContent || node.data || ""; + if (text.trim() === "") return null; + return { + type: "text", + value: text, + attributes: {}, + children: [], + }; + } + + // Handle comment nodes + if (node.nodeType === 8) { + return { + type: "comment", + value: node.textContent || node.data || "", + attributes: {}, + children: [], + }; + } + + // Handle processing instructions + if (node.nodeType === 7) { + return { + type: "processingInstruction", + target: node.target, + value: node.data || "", + attributes: {}, + children: [], + }; + } + + // Handle element nodes + if (node.nodeType === 1) { + const astNode = { + type: "element", + tagName: node.tagName ? node.tagName.toLowerCase() : node.nodeName.toLowerCase(), + attributes: {}, + children: [], + }; + + // Extract attributes + if (node.attributes) { + const attrs = toArray(node.attributes); + for (const attr of attrs) { + if (attr && attr.name) { + astNode.attributes[attr.name] = attr.value; + } + } + } + + // Process child nodes + const children = toArray(node.childNodes); + for (const childNode of children) { + const child = domToAst(childNode); + if (child) { + astNode.children.push(child); + } + } + + // Extract text content (direct text without children elements) + const textContent = children + .filter(n => n && n.nodeType === 3) + .map(n => n.textContent || n.data || "") + .join("") + .trim(); + if (textContent) { + astNode.content = textContent; + } + + return astNode; + } + + // Handle document nodes + if (node.nodeType === 9) { + const astNode = { + type: "document", + attributes: {}, + children: [], + }; + + const children = toArray(node.childNodes); + for (const childNode of children) { + const child = domToAst(childNode); + if (child) { + astNode.children.push(child); + } + } + + return astNode; + } + + return null; +} + +/** + * Parses XML/DITA content into a normalized AST. + * @param {string} content - The XML content to parse. + * @returns {Object|null} The parsed AST, or null if parsing fails. + */ +function parse(content) { + try { + const parser = new DOMParser({ + onError: () => {}, + }); + const doc = parser.parseFromString(content, "text/xml"); + if (!doc || !doc.documentElement) { + return null; + } + return domToAst(doc); + } catch (error) { + return null; + } +} + +module.exports = { parse }; diff --git a/resolver/src/index.test.js b/resolver/src/index.test.js index de8c1c1..bbad6be 100644 --- a/resolver/src/index.test.js +++ b/resolver/src/index.test.js @@ -885,3 +885,224 @@ detectSteps: true expect(codeblockStep).to.exist; }); }); + +// AST-based test detection tests +describe("AST-based Test Detection", function () { + it("should detect markdown code blocks using AST matching", async function () { + const markdownWithCode = `# Test Document + +Here is some bash code: + +\`\`\`bash +echo "Hello from bash" +\`\`\` + +And some JavaScript: + +\`\`\`javascript +console.log("Hello from JS"); +\`\`\` +`; + + const tempMarkdownFile = "temp_ast_markdown.md"; + fs.writeFileSync(tempMarkdownFile, markdownWithCode.trim()); + const config = { + input: tempMarkdownFile, + fileTypes: [ + { + name: "markdown", + extensions: ["md"], + inlineStatements: {}, + markup: [ + { + name: "bashCodeBlock", + ast: { + nodeType: "code", + attributes: { + lang: ["bash", "sh"] + }, + extract: { + "$1": "lang", + "$2": "value" + } + }, + actions: [ + { + runShell: { + command: "$2" + } + } + ] + } + ] + } + ], + }; + const results = await detectAndResolveTests({ config }); + fs.unlinkSync(tempMarkdownFile); + + expect(results.specs).to.be.an("array").that.has.lengthOf(1); + expect(results.specs[0].tests).to.be.an("array").that.has.lengthOf(1); + + const steps = results.specs[0].tests[0].contexts[0].steps; + expect(steps).to.be.an("array").that.has.lengthOf(1); + + // Should only match bash, not javascript + const bashStep = steps.find(s => s.runShell); + expect(bashStep).to.exist; + expect(bashStep.runShell.command).to.include("Hello from bash"); + }); + + it("should combine AST and regex matching (AND operation)", async function () { + const markdownWithCode = ` +\`\`\`bash +echo "regular command" +\`\`\` + +\`\`\`bash +# IMPORTANT: This should match +echo "special command" +\`\`\` +`; + + const tempMarkdownFile = "temp_ast_regex_combo.md"; + fs.writeFileSync(tempMarkdownFile, markdownWithCode.trim()); + const config = { + input: tempMarkdownFile, + fileTypes: [ + { + name: "markdown", + extensions: ["md"], + inlineStatements: {}, + markup: [ + { + name: "importantBashCode", + ast: { + nodeType: "code", + attributes: { + lang: ["bash", "sh"] + }, + extract: { + "$1": "value" + } + }, + regex: ["# IMPORTANT:([\\s\\S]*)"], + actions: [ + { + runShell: { + command: "$1" + } + } + ] + } + ] + } + ], + }; + const results = await detectAndResolveTests({ config }); + fs.unlinkSync(tempMarkdownFile); + + expect(results.specs).to.be.an("array").that.has.lengthOf(1); + expect(results.specs[0].tests).to.be.an("array").that.has.lengthOf(1); + + const steps = results.specs[0].tests[0].contexts[0].steps; + // Should only match the code block with IMPORTANT comment + expect(steps).to.be.an("array").that.has.lengthOf(1); + expect(steps[0].runShell.command).to.include("special command"); + expect(steps[0].runShell.command).not.to.include("regular command"); + }); + + it("should detect XML/DITA elements using AST matching", async function () { + const ditaContent = ` + + Test Topic + + + echo "DITA bash" + print("DITA python") + + +`; + + const tempDitaFile = "temp_ast_dita.dita"; + fs.writeFileSync(tempDitaFile, ditaContent.trim()); + const config = { + input: tempDitaFile, + fileTypes: [ + { + name: "dita", + extensions: ["dita", "xml"], + inlineStatements: { + testStart: [""], + testEnd: [""], + }, + markup: [ + { + name: "ditaBashCodeblock", + ast: { + nodeType: "element", + attributes: { + tagName: "codeblock", + outputclass: ["bash", "shell"] + }, + extract: { + "$1": "attributes.outputclass", + "$2": "content" + } + }, + actions: [ + { + runShell: { + command: "$2" + } + } + ] + } + ] + } + ], + }; + const results = await detectAndResolveTests({ config }); + fs.unlinkSync(tempDitaFile); + + expect(results.specs).to.be.an("array").that.has.lengthOf(1); + expect(results.specs[0].tests).to.be.an("array").that.has.lengthOf(1); + + const steps = results.specs[0].tests[0].contexts[0].steps; + // Should only match bash, not python + expect(steps).to.be.an("array").that.has.lengthOf(1); + expect(steps[0].runShell.command).to.include("DITA bash"); + }); + + it("should support regex-only markup definitions (backward compatibility)", async function () { + const markdownInput = ` +Check this [link](https://example.com/test). +`; + + const tempMarkdownFile = "temp_regex_only.md"; + fs.writeFileSync(tempMarkdownFile, markdownInput.trim()); + const config = { + input: tempMarkdownFile, + fileTypes: [ + { + name: "markdown", + extensions: ["md"], + inlineStatements: {}, + markup: [ + { + name: "checkHyperlink", + regex: ["\\[[^\\]]+\\]\\(\\s*(https?:\\/\\/[^\\s)]+)\\s*\\)"], + actions: ["checkLink"] + } + ] + } + ], + }; + const results = await detectAndResolveTests({ config }); + fs.unlinkSync(tempMarkdownFile); + + expect(results.specs).to.be.an("array").that.has.lengthOf(1); + expect(results.specs[0].tests[0].contexts[0].steps).to.be.an("array").that.has.lengthOf(1); + expect(results.specs[0].tests[0].contexts[0].steps[0].checkLink).to.equal("https://example.com/test"); + }); +}); diff --git a/resolver/src/utils.js b/resolver/src/utils.js index 955b232..9eb462e 100644 --- a/resolver/src/utils.js +++ b/resolver/src/utils.js @@ -11,6 +11,8 @@ const { transformToSchemaKey, readFile, } = require("doc-detective-common"); +const { getOrParse } = require("./ast/cache"); +const { matchNodes, getNodeContent } = require("./ast/matcher"); exports.qualifyFiles = qualifyFiles; exports.parseTests = parseTests; @@ -521,32 +523,138 @@ async function parseContent({ config, content, filePath, fileType }) { }); if (config.detectSteps && fileType.markup) { + // Determine format for AST parsing based on fileType name or extensions + const format = fileType.name || (fileType.extensions && fileType.extensions[0]) || null; + let ast = null; + let astParseFailed = false; + + // Parse AST once for all markup definitions that need it + const hasAstMarkup = fileType.markup.some(markup => markup.ast); + if (hasAstMarkup && format) { + ast = getOrParse(content, format, filePath); + if (!ast) { + astParseFailed = true; + } + } + fileType.markup.forEach((markup) => { - markup.regex.forEach((pattern) => { - const regex = new RegExp(pattern, "g"); - const matches = [...content.matchAll(regex)]; - if (matches.length > 0 && markup.batchMatches) { - // Combine all matches into a single match - const combinedMatch = { - 1: matches.map((match) => match[1] || match[0]).join(os.EOL), - type: "detectedStep", - markup: markup, - sortIndex: Math.min(...matches.map((match) => match.index)), - }; - statements.push(combinedMatch); - } else if (matches.length > 0) { - matches.forEach((match) => { - // Add 'type' property to each match - match.type = "detectedStep"; - match.markup = markup; - // Add 'sortIndex' property to each match - match.sortIndex = match[1] - ? match.index + match[1].length - : match.index; - }); - statements.push(...matches); + // Handle AST-based matching + if (markup.ast) { + // If AST parsing failed, skip this markup definition + if (astParseFailed || !ast) { + return; } - }); + + // Match nodes in the AST + const astMatches = matchNodes(ast, markup.ast); + + if (astMatches.length > 0) { + // If regex is also specified, filter AST matches by regex (AND operation) + if (markup.regex && markup.regex.length > 0) { + astMatches.forEach((astMatch) => { + const nodeContent = getNodeContent(astMatch.node); + let regexMatched = false; + let regexCaptures = {}; + + for (const pattern of (Array.isArray(markup.regex) ? markup.regex : [markup.regex])) { + const regex = new RegExp(pattern); + const regexMatch = nodeContent.match(regex); + if (regexMatch) { + regexMatched = true; + // Merge regex captures with AST extracted values + for (let i = 1; i < regexMatch.length; i++) { + if (regexMatch[i] !== undefined) { + regexCaptures[i] = regexMatch[i]; + } + } + break; + } + } + + if (regexMatched) { + // Merge AST extracted values with regex captures (regex takes precedence) + const mergedCaptures = { ...astMatch.extracted, ...regexCaptures }; + const statement = { + type: "detectedStep", + markup: markup, + sortIndex: astMatch.sortIndex, + }; + // Add captured values to the statement + for (const [key, value] of Object.entries(mergedCaptures)) { + statement[key] = value; + } + statements.push(statement); + } + }); + } else { + // AST-only: use extracted values directly + if (markup.batchMatches) { + // Combine all matches into a single match + const combinedContent = astMatches + .map(m => getNodeContent(m.node)) + .join(os.EOL); + const combinedMatch = { + 1: combinedContent, + type: "detectedStep", + markup: markup, + sortIndex: Math.min(...astMatches.map(m => m.sortIndex)), + }; + // Add extracted values from first match + if (astMatches[0] && astMatches[0].extracted) { + for (const [key, value] of Object.entries(astMatches[0].extracted)) { + combinedMatch[key] = value; + } + } + statements.push(combinedMatch); + } else { + astMatches.forEach((astMatch) => { + const statement = { + type: "detectedStep", + markup: markup, + sortIndex: astMatch.sortIndex, + }; + // Add extracted values + for (const [key, value] of Object.entries(astMatch.extracted)) { + statement[key] = value; + } + // If no $1 extracted, use node content + if (statement[1] === undefined) { + statement[1] = getNodeContent(astMatch.node); + } + statements.push(statement); + }); + } + } + } + } else if (markup.regex) { + // Regex-only matching (original behavior) + const regexPatterns = Array.isArray(markup.regex) ? markup.regex : [markup.regex]; + regexPatterns.forEach((pattern) => { + const regex = new RegExp(pattern, "g"); + const matches = [...content.matchAll(regex)]; + if (matches.length > 0 && markup.batchMatches) { + // Combine all matches into a single match + const combinedMatch = { + 1: matches.map((match) => match[1] || match[0]).join(os.EOL), + type: "detectedStep", + markup: markup, + sortIndex: Math.min(...matches.map((match) => match.index)), + }; + statements.push(combinedMatch); + } else if (matches.length > 0) { + matches.forEach((match) => { + // Add 'type' property to each match + match.type = "detectedStep"; + match.markup = markup; + // Add 'sortIndex' property to each match + match.sortIndex = match[1] + ? match.index + match[1].length + : match.index; + }); + statements.push(...matches); + } + }); + } }); } From e8229633caa670eb4281478e0a3a33eca0892f38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:46:51 +0000 Subject: [PATCH 3/6] Fix code review issues in AST-based detection - Fix format determination to check array length before accessing first element - Improve regex pattern detection to require minimum length between delimiters Co-authored-by: hawkeyexl <5209367+hawkeyexl@users.noreply.github.com> --- resolver/src/ast/matcher.js | 32 +++++++++++++++++++------------- resolver/src/utils.js | 3 ++- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/resolver/src/ast/matcher.js b/resolver/src/ast/matcher.js index 899834c..a28f5a1 100644 --- a/resolver/src/ast/matcher.js +++ b/resolver/src/ast/matcher.js @@ -26,27 +26,33 @@ function matchesPattern(value, pattern) { } // Regex pattern (string starting and ending with /) - if (typeof pattern === "string" && pattern.startsWith("/") && pattern.endsWith("/")) { + // Requires at least one character between delimiters (e.g., /a/ is valid, but // is not) + if (typeof pattern === "string" && pattern.length >= 3 && pattern.startsWith("/") && pattern.endsWith("/")) { const regexStr = pattern.slice(1, -1); - try { - const regex = new RegExp(regexStr); - return regex.test(String(value || "")); - } catch (e) { - return false; + if (regexStr.length > 0) { + try { + const regex = new RegExp(regexStr); + return regex.test(String(value || "")); + } catch (e) { + return false; + } } } // Regex pattern with flags (e.g., /pattern/i) - if (typeof pattern === "string" && pattern.startsWith("/")) { + // Requires at least pattern between delimiters and valid flags + if (typeof pattern === "string" && pattern.length >= 3 && pattern.startsWith("/")) { const lastSlash = pattern.lastIndexOf("/"); - if (lastSlash > 0) { + if (lastSlash > 1) { const regexStr = pattern.slice(1, lastSlash); const flags = pattern.slice(lastSlash + 1); - try { - const regex = new RegExp(regexStr, flags); - return regex.test(String(value || "")); - } catch (e) { - return false; + if (regexStr.length > 0) { + try { + const regex = new RegExp(regexStr, flags); + return regex.test(String(value || "")); + } catch (e) { + return false; + } } } } diff --git a/resolver/src/utils.js b/resolver/src/utils.js index 9eb462e..e23182f 100644 --- a/resolver/src/utils.js +++ b/resolver/src/utils.js @@ -524,7 +524,8 @@ async function parseContent({ config, content, filePath, fileType }) { if (config.detectSteps && fileType.markup) { // Determine format for AST parsing based on fileType name or extensions - const format = fileType.name || (fileType.extensions && fileType.extensions[0]) || null; + const format = fileType.name || + (fileType.extensions && fileType.extensions.length > 0 ? fileType.extensions[0] : null); let ast = null; let astParseFailed = false; From 5a0f37c6e96d325fc505e954e28e91ee3a88572c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:00:37 +0000 Subject: [PATCH 4/6] Fix schema dereferencing for recursive AST schemas - Modify dereferenceSchemas.js to use bundle instead of dereference for config_v3 - Add WeakSet-based cycle detection to deleteDollarIds function - This preserves $refs for recursive schemas like astNodeMatch.children Co-authored-by: hawkeyexl <5209367+hawkeyexl@users.noreply.github.com> --- common/dist/schemas/config_v3.schema.json | 13696 +--- .../dist/schemas/resolvedTests_v3.schema.json | 29856 +------- common/src/schemas/dereferenceSchemas.js | 21 +- .../output_schemas/analytics_v1.schema.json | 585 - .../output_schemas/checkLink_v1.schema.json | 42 - .../output_schemas/click_v1.schema.json | 60 - .../output_schemas/config_v3.schema.json | 13696 +--- .../output_schemas/endRecord_v3.schema.json | 14 - .../output_schemas/find_v1.schema.json | 171 - .../output_schemas/goTo_v1.schema.json | 30 - .../output_schemas/httpRequest_v1.schema.json | 115 - .../output_schemas/matchText_v1.schema.json | 32 - .../output_schemas/moveMouse_v1.schema.json | 60 - .../resolvedTests_v3.schema.json | 32829 --------- .../output_schemas/runShell_v1.schema.json | 35 - .../output_schemas/screenshot_v1.schema.json | 48 - .../output_schemas/scroll_v1.schema.json | 50 - .../startRecording_v1.schema.json | 55 - .../stopRecording_v1.schema.json | 20 - .../output_schemas/type_v1.schema.json | 62 - .../output_schemas/wait_v1.schema.json | 42 - common/src/schemas/schemas.json | 60067 ++-------------- 22 files changed, 10390 insertions(+), 141196 deletions(-) delete mode 100644 common/src/schemas/output_schemas/analytics_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/checkLink_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/click_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/endRecord_v3.schema.json delete mode 100644 common/src/schemas/output_schemas/find_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/goTo_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/httpRequest_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/matchText_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/moveMouse_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/resolvedTests_v3.schema.json delete mode 100644 common/src/schemas/output_schemas/runShell_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/screenshot_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/scroll_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/startRecording_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/stopRecording_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/type_v1.schema.json delete mode 100644 common/src/schemas/output_schemas/wait_v1.schema.json diff --git a/common/dist/schemas/config_v3.schema.json b/common/dist/schemas/config_v3.schema.json index 37355c3..d408b02 100644 --- a/common/dist/schemas/config_v3.schema.json +++ b/common/dist/schemas/config_v3.schema.json @@ -29,18 +29,7 @@ "default": ".", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -173,22 +162,12 @@ "description": "Platforms to run tests on.", "anyOf": [ { - "type": "string", - "enum": [ - "linux", - "mac", - "windows" - ] + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" }, { "type": "array", "items": { - "type": "string", - "enum": [ - "linux", - "mac", - "windows" - ] + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" } } ] @@ -197,148 +176,20 @@ "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." + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browserName" }, { - "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" + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browserName" }, { - "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" + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browser" } ] } @@ -376,15 +227,7 @@ "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." + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browserName" }, "headless": { "type": "boolean", @@ -584,7600 +427,96 @@ "description": "File extensions to use with type.", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, "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" + "$ref": "#/components/schemas/inlineStatements" }, "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": [ - { + "$ref": "#/components/schemas/markupDefinition" + } + } + } + }, + { + "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": [ + { + "$ref": "#/components/schemas/stringOrArray" + } + ] + }, + "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": [ + { + "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/string" + }, + { + "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/object" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", "type": "string", - "enum": [ - "checkLink", - "click", - "find", - "goTo", - "httpRequest", - "loadCookie", - "loadVariables", - "record", - "runCode", - "runShell", - "saveCookie", - "screenshot", - "stopRecord", - "type", - "wait" + "transform": [ + "trim" ] }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string", - "enum": [ - "checkLink", - "click", - "find", - "goTo", - "httpRequest", - "loadCookie", - "loadVariables", - "record", - "runCode", - "runShell", - "saveCookie", - "screenshot", - "stopRecord", - "type", - "wait" + "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" + } ] }, - { - "$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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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": { + "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" @@ -8322,8 +661,7 @@ "description": "Name of the OpenAPI description, as defined in your configuration." }, "descriptionPath": { - "type": "string", - "description": "URL or local path to the OpenAPI description." + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/descriptionPath" }, "definition": { "type": "object", @@ -8333,8 +671,7 @@ "title": "OpenAPI definition" }, "operationId": { - "type": "string", - "description": "ID of the operation to use for the request." + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" }, "server": { "type": "string", @@ -8526,39 +863,7 @@ } }, "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" + "$ref": "#/components/schemas/environment" }, "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.", @@ -8615,27 +920,32 @@ }, "markupDefinition": { "type": "object", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], "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" - } - } - ] + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "$ref": "#/components/schemas/astNodeMatch" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -8648,48 +958,14 @@ "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" - ] + "$ref": "#/components/schemas/markupActionString" }, { "type": "array", "items": { "anyOf": [ { - "type": "string", - "enum": [ - "checkLink", - "click", - "find", - "goTo", - "httpRequest", - "loadCookie", - "loadVariables", - "record", - "runCode", - "runShell", - "saveCookie", - "screenshot", - "stopRecord", - "type", - "wait" - ] + "$ref": "#/components/schemas/markupActionString" }, { "$schema": "http://json-schema.org/draft-07/schema#", @@ -8697,1383 +973,240 @@ "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" + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" }, - { - "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" - } - ] - } + "properties": { + "$schema": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/$schema" }, - "title": "click" - } - ] - }, + "stepId": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/stepId" + }, + "description": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/description" + }, + "unsafe": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/unsafe" + }, + "outputs": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/outputs" + }, + "variables": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/variables" + }, + "breakpoint": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/breakpoint" + } + }, + "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", "required": [ - "find" + "checkLink" ], "properties": { - "find": { + "checkLink": { "$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.", + "title": "checkLink", "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." + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/components/schemas/string" }, { - "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": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/components/schemas/object" + } + ], + "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": "string" - }, - { - "type": "number" + "type": "integer" }, { - "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.", + "type": "array", + "items": { "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." + "type": "integer" } - }, - "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" } - } - ] + ], + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/string" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/object" + }, + { + "type": "boolean" + } ], "components": { "schemas": { "string": { - "title": "Find element (simple)", + "title": "Click element (simple)", "type": "string", - "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + "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": "Find element (detailed)", + "title": "Click element (detailed)", "type": "object", "anyOf": [ { @@ -10112,23 +1245,25 @@ ] } ], - "additionalProperties": false, "properties": { + "button": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" + }, "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." + "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 find. If combined with other element finding fields, the element must match all specified criteria." + "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 find. Supports exact match or regex pattern using /pattern/ syntax." + "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 find. Supports exact match or regex pattern using /pattern/ syntax." + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." }, "elementClass": { "anyOf": [ @@ -10164,283 +1299,174 @@ "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/string" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/object" + } + ], + "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" + ] }, - "timeout": { - "type": "integer", - "description": "Max duration in milliseconds to wait for the element to exist.", - "default": 5000 + { + "required": [ + "elementText" + ] }, - "moveTo": { - "description": "Move to the element. If the element isn't visible, it's scrolled into view.", - "type": "boolean", - "default": true + { + "required": [ + "elementId" + ] }, - "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." - } - } - } - } + { + "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" }, - "examples": [ - true, - "right", - { - "button": "left", - "elementText": "Element text" - }, - { - "selector": "#elementToScreenshot", - "elementText": "Element text", - "button": "middle" - } - ] + { + "type": "number" + }, + { + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click" }, { "type": "object", "properties": { "button": { - "description": "Kind of click to perform.", - "type": "string", - "enum": [ - "left", - "right", - "middle" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" } }, "title": "Find element and click" @@ -10451,248 +1477,7 @@ "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 - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type" }, { "not": { @@ -10743,268 +1528,50 @@ "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." - } - } - } - } - } + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" }, - "title": "Go to URL (detailed)" + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/string" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/object" } ], "components": { @@ -11260,62 +1827,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -11329,616 +1841,60 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" }, { - "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" - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/object" } ], "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": "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": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" + }, + { + "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": [ + { + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0" }, { "type": "object", @@ -12321,373 +2277,30 @@ "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 + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0" } }, - "title": "Common" + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -12701,92 +2314,7 @@ "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)" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/6/allOf/1/properties/runCode/components/schemas/object" } ], "components": { @@ -12925,62 +2453,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -12994,108 +2467,10 @@ "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" - } - ] - } - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" }, { - "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 + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/object" } ], "components": { @@ -13124,23 +2499,7 @@ "type": "object", "properties": { "keys": { - "title": "Type keys (simple)", - "description": "Sequence of keys to enter.", - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - } - ] - } - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" }, "inputDelay": { "type": "number", @@ -13224,279 +2583,42 @@ ] }, { - "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." - } - ] - } - } - } - ] - } - }, - "title": "Capture screenshot (detailed)" - }, - { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/path" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/object" + }, + { "type": "boolean", "title": "Capture screenshot", "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." @@ -13518,13 +2640,7 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/path" }, "directory": { "type": "string", @@ -13558,134 +2674,7 @@ "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." - } - ] - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/crop_element" } ] } @@ -13795,28 +2784,7 @@ "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." + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/padding" } ] } @@ -13892,62 +2860,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -13961,107 +2874,10 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/components/schemas/string" }, { - "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)" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/components/schemas/object" } ], "components": { @@ -14208,62 +3024,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -14277,42 +3038,10 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/components/schemas/string" }, { - "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)" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/components/schemas/object" }, { "type": "boolean", @@ -14365,77 +3094,22 @@ "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." + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" } - }, - "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": "record" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -14465,62 +3139,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "title": "loadVariables", @@ -14530,13 +3149,7 @@ ], "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" - ] + "$ref": "#/properties/loadVariables" } } } @@ -14545,62 +3158,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "title": "dragAndDrop", @@ -14620,222 +3178,12 @@ ], "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 - } - } - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", + "description": "The element to drag." }, "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 - } - } - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", + "description": "The target location to drop the element." }, "duration": { "type": "integer", @@ -14849,108 +3197,10 @@ "elementSpecification": { "anyOf": [ { - "title": "Element (simple)", - "type": "string", - "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/string" }, { - "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 - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/object" } ] }, @@ -15096,78 +3346,23 @@ }, { "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." + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } } - }, - "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" + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "title": "loadCookie", @@ -15182,101 +3377,10 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/components/schemas/string" }, { - "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)" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/components/schemas/object" } ], "components": { @@ -15411,62 +3515,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "title": "wait", @@ -15486,12 +3535,7 @@ "title": "Wait (simple)" }, { - "title": "Wait (environment variable)", - "type": "string", - "pattern": "(\\$[A-Za-z0-9_]+)", - "transform": [ - "trim" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/15/allOf/1/properties/wait/components/schemas/string" }, { "type": "boolean", @@ -15669,223 +3713,108 @@ } }, { - "find": "Find me!" + "find": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/0" + } }, { "find": { - "selector": "[title=Search]" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/1" } }, { "find": { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": "shorthair cat" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/2" } }, { "find": { - "selector": "[title=Search]", - "click": { - "button": "right" - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/3" } }, { "find": { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": { - "keys": [ - "shorthair cat" - ], - "inputDelay": 100 - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/4" } }, { - "click": true + "click": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/0" + } }, { - "click": "right" + "click": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/1" + } }, { "click": { - "button": "left", - "elementText": "Element text" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/2" } }, { "click": { - "selector": "#elementToScreenshot", - "elementText": "Element text", - "button": "middle" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/3" } }, { - "httpRequest": "https://reqres.in/api/users" + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/0" + } }, { "httpRequest": { - "url": "https://reqres.in/api/users" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/1" } }, { "httpRequest": { - "url": "https://reqres.in/api/users/2", - "method": "put", - "request": { - "body": { - "name": "morpheus", - "job": "zion resident" - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/2" } }, { "httpRequest": { - "url": "https://reqres.in/api/users", - "method": "post", - "request": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "response": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "statusCodes": [ - 200, - 201 - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/3" } }, { "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 - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/4" } }, { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/5" } }, { "httpRequest": { - "openApi": "getUserById" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/6" } }, { "httpRequest": { - "openApi": { - "name": "Reqres", - "operationId": "getUserById" - }, - "request": { - "parameters": { - "id": 123 - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/7" } }, { "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "getUserById" - }, - "request": { - "parameters": { - "id": 123 - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/8" } }, { "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "createUser", - "useExample": "both" - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/9" } }, { "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "updateUser", - "useExample": "request", - "exampleKey": "acme" - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/10" } }, { "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "updateUser", - "useExample": "request", - "exampleKey": "acme", - "headers": { - "Authorization": "Bearer $TOKEN" - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/11" } }, { @@ -15918,6 +3847,81 @@ }, "title": "Markup definition" }, + "astNodeMatch": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "$ref": "#/components/schemas/astNodeMatch" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, "markupActionString": { "type": "string", "enum": [ @@ -15946,18 +3950,7 @@ "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" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -15965,18 +3958,7 @@ "description": "Regular expressions that indicate that the current test is complete.", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -15984,18 +3966,7 @@ "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" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -16003,18 +3974,7 @@ "description": "Regular expressions that indicate that the ignored section of content is complete.", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -16022,18 +3982,7 @@ "description": "Regular expressions that indicate a step in a test.", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] } @@ -16159,6 +4108,79 @@ }, { "crawl": true + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": [ + "md" + ], + "markup": [ + { + "name": "bashCodeBlock", + "ast": { + "nodeType": "code", + "attributes": { + "lang": [ + "bash", + "sh" + ] + }, + "extract": { + "$1": "attributes.lang", + "$2": "value" + } + }, + "actions": [ + { + "runCode": { + "language": "$1", + "code": "$2" + } + } + ] + } + ] + } + ] + }, + { + "fileTypes": [ + { + "extends": "dita", + "extensions": [ + "dita", + "xml" + ], + "markup": [ + { + "name": "ditaCodeblock", + "ast": { + "nodeType": "element", + "attributes": { + "tagName": "codeblock", + "outputclass": [ + "bash", + "shell" + ] + }, + "extract": { + "$1": "attributes.outputclass", + "$2": "content" + } + }, + "actions": [ + { + "runShell": { + "command": "$2" + } + } + ] + } + ] + } + ] } ] } \ No newline at end of file diff --git a/common/dist/schemas/resolvedTests_v3.schema.json b/common/dist/schemas/resolvedTests_v3.schema.json index a0f89f7..0de7347 100644 --- a/common/dist/schemas/resolvedTests_v3.schema.json +++ b/common/dist/schemas/resolvedTests_v3.schema.json @@ -196,12 +196,7 @@ { "type": "array", "items": { - "type": "string", - "enum": [ - "linux", - "mac", - "windows" - ] + "type": "string" } } ] @@ -231,12 +226,6 @@ "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": { @@ -286,71 +275,12 @@ { "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" } ] @@ -362,81 +292,17 @@ "components": { "schemas": { "platform": { - "type": "string", - "enum": [ - "linux", - "mac", - "windows" - ] + "type": "string" }, "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" } } @@ -596,20 +462,7 @@ "extensions": { "description": "File extensions to use with type.", "anyOf": [ - { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] - } + {} ] }, "inlineStatements": { @@ -619,96 +472,31 @@ "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" - } - } - ] - } + {} ] } }, @@ -720,28 +508,105 @@ "minItems": 1, "items": { "type": "object", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], "properties": { "name": { "description": "Name of the markup definition", "type": "string" }, - "regex": { - "description": "Regular expressions to match the markup type.", - "anyOf": [ - { + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", "anyOf": [ { "type": "string" }, { "type": "array", - "minItems": 1, "items": { "type": "string" } } ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": {}, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] } + }, + "title": "AST node match configuration" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + {} ] }, "batchMatches": { @@ -777,24 +642,7 @@ "items": { "anyOf": [ { - "type": "string", - "enum": [ - "checkLink", - "click", - "find", - "goTo", - "httpRequest", - "loadCookie", - "loadVariables", - "record", - "runCode", - "runShell", - "saveCookie", - "screenshot", - "stopRecord", - "type", - "wait" - ] + "type": "string" }, { "$schema": "http://json-schema.org/draft-07/schema#", @@ -863,10 +711,7 @@ }, "$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" - ] + "type": "string" }, "stepId": { "type": "string", @@ -884,25 +729,11 @@ "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": { @@ -917,60 +748,6 @@ "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" }, { @@ -1050,61 +827,13 @@ "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" - ] + "pattern": "(^(http://|https://|\\/).*|\\$[A-Za-z0-9_]+$)" }, "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 - ] - } - } + "additionalProperties": false } } }, @@ -1133,60 +862,6 @@ "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" }, { @@ -1321,115 +996,11 @@ }, "button": { "description": "Kind of click to perform.", - "type": "string", - "enum": [ - "left", - "right", - "middle" - ] + "type": "string" }, "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." - } - } + "type": "object" } } }, @@ -1456,60 +1027,6 @@ "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" }, { @@ -1637,266 +1154,14 @@ { "$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" - } - ] + "description": "Click or tap an element." }, { "type": "object", "properties": { "button": { "description": "Kind of click to perform.", - "type": "string", - "enum": [ - "left", - "right", - "middle" - ] + "type": "string" } }, "title": "Find element and click" @@ -1936,22 +1201,7 @@ "properties": { "keys": { "title": "Type keys (simple)", - "description": "Sequence of keys to enter.", - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - } - ] - } - } - ] + "description": "Sequence of keys to enter." }, "inputDelay": { "type": "number", @@ -2020,106 +1270,11 @@ "schemas": { "keys": { "title": "Type keys (simple)", - "description": "Sequence of keys to enter.", - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - } - ] - } - } - ] + "description": "Sequence of keys to enter." }, "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 } } @@ -2180,695 +1335,338 @@ "object": { "title": "Find element (detailed)", "type": "object", - "anyOf": [ - { - "required": [ - "selector" - ] - }, - { - "required": [ - "elementText" - ] - }, - { - "required": [ - "elementId" - ] - }, - { - "required": [ - "elementTestId" - ] - }, - { - "required": [ - "elementClass" - ] - }, - { - "required": [ - "elementAttribute" - ] - }, - { - "required": [ - "elementAria" - ] - } + "additionalProperties": false + } + } + }, + "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" ], - "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" + "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", + "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" } - } - ], - "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." - }, - "elementAttribute": { - "type": "object", - "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", - "additionalProperties": { + ], + "default": 500 + }, + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", "anyOf": [ { - "type": "string" + "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" + ] }, { - "type": "number" + "required": [ + "elementAttribute" + ] }, { - "type": "boolean" + "required": [ + "elementAria" + ] } - ] - } - }, - "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" - ] + ], + "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" }, - "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." - } + { + "type": "array", + "items": { + "type": "string" } } - } - }, - "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" - ] - } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." }, - "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.", + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { "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" - } - ] - } + "type": "number" }, - "elementAria": { - "type": "string", - "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + { + "type": "boolean" } - }, - "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" + }, + "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_]+)" + }, + "object": { + "description": "Navigate to an HTTP or HTTPS URL.", + "type": "object", + "additionalProperties": false, + "title": "Go to URL (detailed)" } } }, "examples": [ - "Find me!", + "https://www.google.com", + "/search", { - "selector": "[title=Search]" + "url": "https://www.google.com" }, { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": "shorthair cat" + "url": "/search", + "origin": "https://www.google.com" }, { - "selector": "[title=Search]", - "click": { - "button": "right" + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 } }, { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": { - "keys": [ - "shorthair cat" - ], - "inputDelay": 100 + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } } }, { - "elementId": "/^user-[0-9]+$/", - "elementClass": [ - "admin", - "/^level-[1-5]$/" - ], - "elementAttribute": { - "data-active": true, - "data-score": "/^[0-9]+$/" - }, - "timeout": 8000, - "moveTo": false + "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": "find" + "title": "goTo" } ] }, @@ -2876,859 +1674,312 @@ "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" + "httpRequest" ], "properties": { - "goTo": { + "httpRequest": { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "goTo", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", "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.", + "title": "HTTP request (simple)", "type": "string", - "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", "transform": [ "trim" ] }, { - "description": "Navigate to an HTTP or HTTPS URL.", + "title": "HTTP request (detailed)", "type": "object", - "additionalProperties": false, - "required": [ - "url" + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } ], + "additionalProperties": false, "properties": { "url": { + "title": "HTTP request (simple)", "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 + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)" }, - "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": [ + "openApi": { + "anyOf": [ + { + "allOf": [ { - "type": "integer", - "minimum": 0 + "type": "string", + "description": "ID of the operation to use for the request." }, { - "type": "null" + "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." } - ], - "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" - ] - }, + { + "allOf": [ { - "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": { + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, "anyOf": [ { - "type": "string" + "required": [ + "descriptionPath" + ] }, { - "type": "array", - "items": { - "type": "string" - } + "required": [ + "operationId" + ] } ], - "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." - }, - "elementAttribute": { - "type": "object", - "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "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": [ - { + "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" }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + "title": "OpenAPI request headers" + } }, - "elementAttribute": { - "type": "object", - "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - } - ] + "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." + } } }, - "elementAria": { - "type": "string", - "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." - } + "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)" } - } + ] } - } + ] }, - "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" + "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 ] }, - { - "required": [ - "openApi" - ] - } - ], - "additionalProperties": false, - "properties": { - "url": { - "title": "HTTP request (simple)", + "method": { "type": "string", - "description": "URL for the HTTP request.", - "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], "transform": [ - "trim" - ] + "trim", + "toEnumCase" + ], + "default": "get" }, - "openApi": { - "anyOf": [ - { - "allOf": [ + "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": [ { - "type": "string", - "description": "ID of the operation to use for the request." + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} }, { - "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." + "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" } ] }, - { - "allOf": [ + "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": [ { - "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.", + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", "type": "object", "additionalProperties": true, "properties": {} @@ -3836,397 +2087,12 @@ "title": "HTTP request (simple)", "type": "string", "description": "URL for the HTTP request.", - "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", - "transform": [ - "trim" - ] + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)" }, "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" - } - } + "additionalProperties": false } } }, @@ -4431,60 +2297,6 @@ "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" }, { @@ -4591,88 +2403,11 @@ "string": { "title": "Run shell command (simple)", "description": "Command to perform in the machine's default shell.", - "type": "string", - "transform": [ - "trim" - ] + "type": "string" }, "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)" } } @@ -4738,60 +2473,6 @@ "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" }, { @@ -4898,90 +2579,6 @@ "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)" } } @@ -5031,60 +2628,6 @@ "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" }, { @@ -5096,344 +2639,48 @@ "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$`.", + "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$`." + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "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": "Type keys (simple)", - "description": "Sequence of keys to enter.", - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - } - ] - } - } + "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" ] }, { - "title": "Type keys (detailed)", "type": "object", + "additionalProperties": false, "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": { + "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", - "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" - ] + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)" }, "directory": { "type": "string", @@ -5613,341 +2860,22 @@ "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" - ] + "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)" }, "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." - } - ] - } - } - } - ] - } - }, "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." - } - ] - } - } + "additionalProperties": false }, "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." } @@ -5998,60 +2926,6 @@ "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" }, { @@ -6175,103 +3049,11 @@ "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" - ] + "pattern": "^[A-Za-z0-9_./\\-]+$" }, "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)" } } @@ -6314,60 +3096,6 @@ "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" }, { @@ -6431,38 +3159,10 @@ "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" - ] + "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)" }, "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)" } } @@ -6486,60 +3186,6 @@ "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" }, { @@ -6571,60 +3217,6 @@ "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" }, { @@ -6638,10 +3230,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "loadVariables", "type": "string", - "description": "Load environment variables from the specified `.env` file.", - "examples": [ - ".env" - ] + "description": "Load environment variables from the specified `.env` file." } } } @@ -6651,60 +3240,6 @@ "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" }, { @@ -6835,112 +3370,7 @@ }, "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 - } - } - } - ] + "anyOf": [] }, "duration": { "type": "integer", @@ -6952,112 +3382,7 @@ "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 - } - } - } - ] + "anyOf": [] }, "string": { "title": "Element (simple)", @@ -7066,102 +3391,7 @@ }, "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 - } - } + "type": "object" } } }, @@ -7218,60 +3448,6 @@ "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" }, { @@ -7390,97 +3566,11 @@ "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" - ] + "pattern": "^[A-Za-z0-9_./\\-]+$" }, "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)" } } @@ -7517,60 +3607,6 @@ "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" }, { @@ -7608,10 +3644,7 @@ "string": { "title": "Wait (environment variable)", "type": "string", - "pattern": "(\\$[A-Za-z0-9_]+)", - "transform": [ - "trim" - ] + "pattern": "(\\$[A-Za-z0-9_]+)" } } }, @@ -7793,10 +3826,7 @@ }, { "find": { - "selector": "[title=Search]", - "click": { - "button": "right" - } + "selector": "[title=Search]" } }, { @@ -7805,13 +3835,7 @@ "timeout": 10000, "elementText": "Search", "moveTo": true, - "click": true, - "type": { - "keys": [ - "shorthair cat" - ], - "inputDelay": 100 - } + "click": true } }, { @@ -7844,86 +3868,26 @@ { "httpRequest": { "url": "https://reqres.in/api/users/2", - "method": "put", - "request": { - "body": { - "name": "morpheus", - "job": "zion resident" - } - } + "method": "put" } }, { "httpRequest": { "url": "https://reqres.in/api/users", - "method": "post", - "request": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "response": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "statusCodes": [ - 200, - 201 - ] + "method": "post" } }, { "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 - ] + "timeout": 30000 } }, { "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, @@ -7936,62 +3900,19 @@ } }, { - "httpRequest": { - "openApi": { - "name": "Reqres", - "operationId": "getUserById" - }, - "request": { - "parameters": { - "id": 123 - } - } - } + "httpRequest": {} }, { - "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "getUserById" - }, - "request": { - "parameters": { - "id": 123 - } - } - } + "httpRequest": {} }, { - "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "createUser", - "useExample": "both" - } - } + "httpRequest": {} }, { - "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "updateUser", - "useExample": "request", - "exampleKey": "acme" - } - } + "httpRequest": {} }, { - "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "updateUser", - "useExample": "request", - "exampleKey": "acme", - "headers": { - "Authorization": "Bearer $TOKEN" - } - } - } + "httpRequest": {} }, { "stepId": "breakpoint-example", @@ -8037,20 +3958,7 @@ "extensions": { "description": "File extensions to use with type.", "anyOf": [ - { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] - } + {} ] }, "runShell": { @@ -8059,238 +3967,7 @@ { "$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" - } - ] + "description": "Perform a native shell command." } ] } @@ -8316,161 +3993,7 @@ "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" - } - } - ] + "additionalProperties": false }, { "type": "object", @@ -8596,23486 +4119,336 @@ "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 + "title": "Markup definition" + }, + "astNodeMatch": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "title": "AST node match configuration" + }, + "markupActionString": { + "type": "string" + }, + "inlineStatements": { + "description": "Statements to include tests and steps inside the content of the file, such as within Markdown.", + "type": "object", + "title": "Inline statement definition" + }, + "stringOrArray": {} + } + }, + "examples": [ + {}, + { + "input": ".", + "output": ".", + "recursive": true, + "loadVariables": ".env", + "fileTypes": [ + "markdown" + ] + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": [ + "md", + "markdown", + "mdx" + ], + "inlineStatements": { + "testStart": "", + "testEnd": "", + "ignoreStart": "", + "ignoreEnd": "", + "step": "" }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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 - } - ] - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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" - } - } - } - ] + "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 + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": [ + "md" + ], + "markup": [ + { + "name": "bashCodeBlock", + "ast": { + "nodeType": "code", + "attributes": { + "lang": [ + "bash", + "sh" + ] + }, + "extract": { + "$1": "attributes.lang", + "$2": "value" + } + }, + "actions": [ + { + "runCode": { + "language": "$1", + "code": "$2" + } + } + ] + } + ] + } + ] + }, + { + "fileTypes": [ + { + "extends": "dita", + "extensions": [ + "dita", + "xml" + ], + "markup": [ + { + "name": "ditaCodeblock", + "ast": { + "nodeType": "element", + "attributes": { + "tagName": "codeblock", + "outputclass": [ + "bash", + "shell" + ] + }, + "extract": { + "$1": "attributes.outputclass", + "$2": "content" + } + }, + "actions": [ + { + "runShell": { + "command": "$2" + } + } + ] + } + ] + } + ] + } + ] + }, + "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." + }, + "openApi": { + "type": "array" + }, + "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." + }, + "openApi": { + "type": "array" + }, + "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" + } + }, + "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.", + "additionalProperties": false, + "title": "Browser" + }, + "openApi": { + "type": "array" + }, + "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" } } }, @@ -32102,186 +4475,7 @@ "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)" - } - ] - } + "type": "array" } } }, diff --git a/common/src/schemas/dereferenceSchemas.js b/common/src/schemas/dereferenceSchemas.js index cd1d7c5..5b806f2 100644 --- a/common/src/schemas/dereferenceSchemas.js +++ b/common/src/schemas/dereferenceSchemas.js @@ -112,8 +112,18 @@ async function dereferenceSchemas() { let schema = fs.readFileSync(filePath).toString(); schema = JSON.parse(schema); - // Dereference schema - schema = await parser.dereference(schema); + // Check if this is config_v3 which has recursive schemas (astNodeMatch) + // For recursive schemas, use bundle instead of dereference to preserve $refs + const hasRecursiveSchemas = file.includes('config_v3'); + + if (hasRecursiveSchemas) { + // Bundle keeps $refs for recursive schemas while resolving others + schema = await parser.bundle(schema); + } else { + // Dereference fully resolves all $refs + schema = await parser.dereference(schema); + } + // Delete $id attributes schema = deleteDollarIds(schema); @@ -189,13 +199,16 @@ function updateRefPaths(schema) { * Recursively removes all `$id` properties from a JSON schema object. * * @param {object} schema - The JSON schema object to process. + * @param {WeakSet} seen - Set of already visited objects to handle circular references. * @returns {object} The schema object with all `$id` properties deleted. */ -function deleteDollarIds(schema) { +function deleteDollarIds(schema, seen = new WeakSet()) { if (schema === null || typeof schema !== "object") return schema; + if (seen.has(schema)) return schema; + seen.add(schema); for (let [key, value] of Object.entries(schema)) { if (typeof value === "object") { - deleteDollarIds(value); + deleteDollarIds(value, seen); } if (key === "$id") { delete schema[key]; diff --git a/common/src/schemas/output_schemas/analytics_v1.schema.json b/common/src/schemas/output_schemas/analytics_v1.schema.json deleted file mode 100644 index 9b369ee..0000000 --- a/common/src/schemas/output_schemas/analytics_v1.schema.json +++ /dev/null @@ -1,585 +0,0 @@ -{ - "title": "analytics", - "type": "object", - "description": "Perform a native shell command.", - "additionalProperties": false, - "properties": { - "version": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "detailLevel": { - "type": "string", - "enum": [ - "run", - "tests", - "action-simple", - "action-detailed" - ] - }, - "tests": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberTests": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - } - }, - "required": [ - "numberTests", - "passed", - "failed" - ] - }, - "actions": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberActions": { - "type": "integer" - }, - "averageNumberActionsPerTest": { - "type": "integer" - }, - "maxActionsPerTest": { - "type": "integer" - }, - "minActionsPerTest": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - } - }, - "required": [ - "numberActions", - "averageNumberActionsPerTest", - "maxActionsPerTest", - "minActionsPerTest", - "passed", - "failed" - ] - }, - "actionDetails": { - "type": "object", - "additionalProperties": false, - "properties": { - "goTo": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "uri": { - "type": "integer" - } - }, - "required": [ - "numberInstances", - "passed", - "failed", - "uri" - ] - }, - "find": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "wait": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "duration": { - "type": "integer" - } - } - }, - "matchText": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "text": { - "type": "integer" - } - } - }, - "moveMouse": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "alignH": { - "type": "integer" - }, - "alignV": { - "type": "integer" - }, - "offsetX": { - "type": "integer" - }, - "offsetY": { - "type": "integer" - } - } - }, - "click": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - } - } - }, - "type": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "keys": { - "type": "integer" - }, - "trailingSpecialKey": { - "type": "integer" - }, - "env": { - "type": "integer" - } - } - } - } - }, - "matchText": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "css": { - "type": "integer" - }, - "text": { - "type": "integer" - } - } - }, - "click": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "css": { - "type": "integer" - } - } - }, - "type": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "css": { - "type": "integer" - }, - "keys": { - "type": "integer" - }, - "trailingSpecialKey": { - "type": "integer" - }, - "env": { - "type": "integer" - } - } - }, - "moveMouse": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "css": { - "type": "integer" - }, - "alignH": { - "type": "integer" - }, - "alignV": { - "type": "integer" - }, - "offsetX": { - "type": "integer" - }, - "offsetY": { - "type": "integer" - } - } - }, - "scroll": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "x": { - "type": "integer" - }, - "y": { - "type": "integer" - } - } - }, - "wait": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "duration": { - "type": "integer" - }, - "css": { - "type": "integer" - } - } - }, - "screenshot": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "mediaDirectory": { - "type": "integer" - }, - "filename": { - "type": "integer" - }, - "matchPrevious": { - "type": "integer" - }, - "matchThreshold": { - "type": "integer" - } - } - }, - "startRecording": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "mediaDirectory": { - "type": "integer" - }, - "filename": { - "type": "integer" - }, - "gifFps": { - "type": "integer" - }, - "gifWidth": { - "type": "integer" - } - } - }, - "stopRecording": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - } - } - }, - "checkLink": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "uri": { - "type": "integer" - }, - "statusCodes": { - "type": "integer" - } - } - }, - "runShell": { - "type": "object", - "additionalProperties": false, - "properties": { - "numberInstances": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "failed": { - "type": "integer" - }, - "command": { - "type": "integer" - }, - "env": { - "type": "integer" - } - } - } - } - } - }, - "required": [ - "version", - "detailLevel" - ], - "examples": [ - { - "version": "0.1.8", - "userId": "", - "detailLevel": "action-detailed", - "tests": { - "numberTests": 0, - "passed": 0, - "failed": 0 - }, - "actions": { - "numberActions": 0, - "averageNumberActionsPerTest": 0, - "maxActionsPerTest": 0, - "minActionsPerTest": 0, - "passed": 0, - "failed": 0 - }, - "actionDetails": { - "goTo": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "uri": 0 - }, - "find": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "wait": { - "numberInstances": 0, - "duration": 0 - }, - "matchText": { - "numberInstances": 0, - "text": 0 - }, - "moveMouse": { - "numberInstances": 0, - "alignH": 0, - "alignV": 0, - "offsetX": 0, - "offsetY": 0 - }, - "click": { - "numberInstances": 0 - }, - "type": { - "numberInstances": 0, - "keys": 0, - "trailingSpecialKey": 0, - "env": 0 - } - }, - "matchText": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "css": 0, - "text": 0 - }, - "click": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "css": 0 - }, - "type": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "css": 0, - "keys": 0, - "trailingSpecialKey": 0, - "env": 0 - }, - "moveMouse": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "css": 0, - "alignH": 0, - "alignV": 0, - "offsetX": 0, - "offsetY": 0 - }, - "scroll": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "x": 0, - "y": 0 - }, - "wait": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "duration": 0, - "css": 0 - }, - "screenshot": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "mediaDirectory": 0, - "filename": 0, - "matchPrevious": 0, - "matchThreshold": 0 - }, - "startRecording": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "mediaDirectory": 0, - "filename": 0, - "gifFps": 0, - "gifWidth": 0 - }, - "stopRecording": { - "numberInstances": 0, - "passed": 0, - "failed": 0 - }, - "checkLink": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "uri": 0, - "statusCodes": 0 - }, - "runShell": { - "numberInstances": 0, - "passed": 0, - "failed": 0, - "command": 0, - "env": 0 - } - } - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/checkLink_v1.schema.json b/common/src/schemas/output_schemas/checkLink_v1.schema.json deleted file mode 100644 index b7903bc..0000000 --- a/common/src/schemas/output_schemas/checkLink_v1.schema.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "title": "checkLink", - "type": "object", - "description": "Check if a URI returns an acceptable status code from a GET request.", - "properties": { - "action": { - "type": "string", - "const": "checkLink" - }, - "uri": { - "type": "string", - "description": "URI to check." - }, - "statusCodes": { - "type": "array", - "items": { - "type": "integer" - }, - "default": [ - 200 - ] - } - }, - "required": [ - "action", - "uri" - ], - "additionalProperties": false, - "examples": [ - { - "action": "checkLink", - "uri": "https://www.google.com" - }, - { - "action": "checkLink", - "uri": "https://www.google.com", - "statusCodes": [ - 200 - ] - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/click_v1.schema.json b/common/src/schemas/output_schemas/click_v1.schema.json deleted file mode 100644 index 15f6b4c..0000000 --- a/common/src/schemas/output_schemas/click_v1.schema.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "title": "click", - "type": "object", - "description": "Click an element specified by a CSS sepector.", - "properties": { - "action": { - "type": "string", - "const": "click" - }, - "css": { - "type": "string", - "description": "CSS selector that uniquely identified the element." - }, - "alignH": { - "type": "string", - "description": "Horizantal alignment of the mouse to the element.", - "enum": [ - "left", - "center", - "right" - ] - }, - "alignV": { - "type": "string", - "description": "Vertical alignment of the mouse to the element.", - "enum": [ - "left", - "center", - "right" - ] - }, - "offsetX": { - "type": "integer", - "description": "Number of pixels to offset the mouse along the X axis, relative to the element center. Positive values offset to the right. Negative values offset to the left." - }, - "offsetY": { - "type": "integer", - "description": "Number of pixels to offset the mouse along the Y axis, relative to the element center. Positive values offset to the top. Negative values offset to the bottom." - } - }, - "required": [ - "action", - "css" - ], - "additionalProperties": false, - "examples": [ - { - "action": "click", - "css": "#gbqfbb" - }, - { - "action": "click", - "css": "#gbqfbb", - "alignH": "center", - "alignV": "center", - "offsetX": 10, - "offsetY": 10 - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/config_v3.schema.json b/common/src/schemas/output_schemas/config_v3.schema.json index 37355c3..d408b02 100644 --- a/common/src/schemas/output_schemas/config_v3.schema.json +++ b/common/src/schemas/output_schemas/config_v3.schema.json @@ -29,18 +29,7 @@ "default": ".", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -173,22 +162,12 @@ "description": "Platforms to run tests on.", "anyOf": [ { - "type": "string", - "enum": [ - "linux", - "mac", - "windows" - ] + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" }, { "type": "array", "items": { - "type": "string", - "enum": [ - "linux", - "mac", - "windows" - ] + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" } } ] @@ -197,148 +176,20 @@ "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." + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browserName" }, { - "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" + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browserName" }, { - "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" + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browser" } ] } @@ -376,15 +227,7 @@ "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." + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browserName" }, "headless": { "type": "boolean", @@ -584,7600 +427,96 @@ "description": "File extensions to use with type.", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, "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" + "$ref": "#/components/schemas/inlineStatements" }, "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": [ - { + "$ref": "#/components/schemas/markupDefinition" + } + } + } + }, + { + "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": [ + { + "$ref": "#/components/schemas/stringOrArray" + } + ] + }, + "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": [ + { + "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/string" + }, + { + "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/object" + } + ], + "components": { + "schemas": { + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", "type": "string", - "enum": [ - "checkLink", - "click", - "find", - "goTo", - "httpRequest", - "loadCookie", - "loadVariables", - "record", - "runCode", - "runShell", - "saveCookie", - "screenshot", - "stopRecord", - "type", - "wait" + "transform": [ + "trim" ] }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string", - "enum": [ - "checkLink", - "click", - "find", - "goTo", - "httpRequest", - "loadCookie", - "loadVariables", - "record", - "runCode", - "runShell", - "saveCookie", - "screenshot", - "stopRecord", - "type", - "wait" + "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" + } ] }, - { - "$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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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": { + "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" @@ -8322,8 +661,7 @@ "description": "Name of the OpenAPI description, as defined in your configuration." }, "descriptionPath": { - "type": "string", - "description": "URL or local path to the OpenAPI description." + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/descriptionPath" }, "definition": { "type": "object", @@ -8333,8 +671,7 @@ "title": "OpenAPI definition" }, "operationId": { - "type": "string", - "description": "ID of the operation to use for the request." + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" }, "server": { "type": "string", @@ -8526,39 +863,7 @@ } }, "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" + "$ref": "#/components/schemas/environment" }, "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.", @@ -8615,27 +920,32 @@ }, "markupDefinition": { "type": "object", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], "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" - } - } - ] + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "$ref": "#/components/schemas/astNodeMatch" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -8648,48 +958,14 @@ "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" - ] + "$ref": "#/components/schemas/markupActionString" }, { "type": "array", "items": { "anyOf": [ { - "type": "string", - "enum": [ - "checkLink", - "click", - "find", - "goTo", - "httpRequest", - "loadCookie", - "loadVariables", - "record", - "runCode", - "runShell", - "saveCookie", - "screenshot", - "stopRecord", - "type", - "wait" - ] + "$ref": "#/components/schemas/markupActionString" }, { "$schema": "http://json-schema.org/draft-07/schema#", @@ -8697,1383 +973,240 @@ "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" + "schemas": { + "common": { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" }, - { - "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" - } - ] - } + "properties": { + "$schema": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/$schema" }, - "title": "click" - } - ] - }, + "stepId": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/stepId" + }, + "description": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/description" + }, + "unsafe": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/unsafe" + }, + "outputs": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/outputs" + }, + "variables": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/variables" + }, + "breakpoint": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/breakpoint" + } + }, + "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", "required": [ - "find" + "checkLink" ], "properties": { - "find": { + "checkLink": { "$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.", + "title": "checkLink", "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." + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/components/schemas/string" }, { - "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": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/components/schemas/object" + } + ], + "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": "string" - }, - { - "type": "number" + "type": "integer" }, { - "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.", + "type": "array", + "items": { "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." + "type": "integer" } - }, - "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" } - } - ] + ], + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/string" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/object" + }, + { + "type": "boolean" + } ], "components": { "schemas": { "string": { - "title": "Find element (simple)", + "title": "Click element (simple)", "type": "string", - "description": "Identifier for the element to find. Can be a selector, element text, ARIA name, ID, or test ID." + "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": "Find element (detailed)", + "title": "Click element (detailed)", "type": "object", "anyOf": [ { @@ -10112,23 +1245,25 @@ ] } ], - "additionalProperties": false, "properties": { + "button": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" + }, "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." + "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 find. If combined with other element finding fields, the element must match all specified criteria." + "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 find. Supports exact match or regex pattern using /pattern/ syntax." + "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 find. Supports exact match or regex pattern using /pattern/ syntax." + "description": "data-testid attribute of the element to click. Supports exact match or regex pattern using /pattern/ syntax." }, "elementClass": { "anyOf": [ @@ -10164,283 +1299,174 @@ "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/string" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/object" + } + ], + "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" + ] }, - "timeout": { - "type": "integer", - "description": "Max duration in milliseconds to wait for the element to exist.", - "default": 5000 + { + "required": [ + "elementText" + ] }, - "moveTo": { - "description": "Move to the element. If the element isn't visible, it's scrolled into view.", - "type": "boolean", - "default": true + { + "required": [ + "elementId" + ] }, - "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." - } - } - } - } + { + "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" }, - "examples": [ - true, - "right", - { - "button": "left", - "elementText": "Element text" - }, - { - "selector": "#elementToScreenshot", - "elementText": "Element text", - "button": "middle" - } - ] + { + "type": "number" + }, + { + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click" }, { "type": "object", "properties": { "button": { - "description": "Kind of click to perform.", - "type": "string", - "enum": [ - "left", - "right", - "middle" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" } }, "title": "Find element and click" @@ -10451,248 +1477,7 @@ "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 - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type" }, { "not": { @@ -10743,268 +1528,50 @@ "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." - } - } - } - } - } + ], + "inputDelay": 100 + } + }, + { + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" }, - "title": "Go to URL (detailed)" + "timeout": 8000, + "moveTo": false + } + ] + } + }, + "title": "find" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/string" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/object" } ], "components": { @@ -11260,62 +1827,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -11329,616 +1841,60 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" }, { - "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" - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/object" } ], "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": "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": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" + }, + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" + }, + { + "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": [ + { + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0" }, { "type": "object", @@ -12321,373 +2277,30 @@ "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 + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0" } }, - "title": "Common" + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -12701,92 +2314,7 @@ "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)" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/6/allOf/1/properties/runCode/components/schemas/object" } ], "components": { @@ -12925,62 +2453,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -12994,108 +2467,10 @@ "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" - } - ] - } - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" }, { - "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 + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/object" } ], "components": { @@ -13124,23 +2499,7 @@ "type": "object", "properties": { "keys": { - "title": "Type keys (simple)", - "description": "Sequence of keys to enter.", - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - } - ] - } - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" }, "inputDelay": { "type": "number", @@ -13224,279 +2583,42 @@ ] }, { - "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." - } - ] - } - } - } - ] - } - }, - "title": "Capture screenshot (detailed)" - }, - { + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/path" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/object" + }, + { "type": "boolean", "title": "Capture screenshot", "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." @@ -13518,13 +2640,7 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/path" }, "directory": { "type": "string", @@ -13558,134 +2674,7 @@ "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." - } - ] - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/crop_element" } ] } @@ -13795,28 +2784,7 @@ "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." + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/padding" } ] } @@ -13892,62 +2860,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -13961,107 +2874,10 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/components/schemas/string" }, { - "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)" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/components/schemas/object" } ], "components": { @@ -14208,62 +3024,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -14277,42 +3038,10 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/components/schemas/string" }, { - "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)" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/components/schemas/object" }, { "type": "boolean", @@ -14365,77 +3094,22 @@ "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." + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" } - }, - "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": "record" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "type": "object", @@ -14465,62 +3139,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "title": "loadVariables", @@ -14530,13 +3149,7 @@ ], "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" - ] + "$ref": "#/properties/loadVariables" } } } @@ -14545,62 +3158,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "title": "dragAndDrop", @@ -14620,222 +3178,12 @@ ], "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 - } - } - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", + "description": "The element to drag." }, "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 - } - } - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", + "description": "The target location to drop the element." }, "duration": { "type": "integer", @@ -14849,108 +3197,10 @@ "elementSpecification": { "anyOf": [ { - "title": "Element (simple)", - "type": "string", - "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/string" }, { - "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 - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/object" } ] }, @@ -15096,78 +3346,23 @@ }, { "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." + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" + } } - }, - "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" + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "title": "loadCookie", @@ -15182,101 +3377,10 @@ "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" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/components/schemas/string" }, { - "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)" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/components/schemas/object" } ], "components": { @@ -15411,62 +3515,7 @@ { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" }, { "title": "wait", @@ -15486,12 +3535,7 @@ "title": "Wait (simple)" }, { - "title": "Wait (environment variable)", - "type": "string", - "pattern": "(\\$[A-Za-z0-9_]+)", - "transform": [ - "trim" - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/15/allOf/1/properties/wait/components/schemas/string" }, { "type": "boolean", @@ -15669,223 +3713,108 @@ } }, { - "find": "Find me!" + "find": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/0" + } }, { "find": { - "selector": "[title=Search]" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/1" } }, { "find": { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": "shorthair cat" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/2" } }, { "find": { - "selector": "[title=Search]", - "click": { - "button": "right" - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/3" } }, { "find": { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": { - "keys": [ - "shorthair cat" - ], - "inputDelay": 100 - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/4" } }, { - "click": true + "click": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/0" + } }, { - "click": "right" + "click": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/1" + } }, { "click": { - "button": "left", - "elementText": "Element text" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/2" } }, { "click": { - "selector": "#elementToScreenshot", - "elementText": "Element text", - "button": "middle" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/3" } }, { - "httpRequest": "https://reqres.in/api/users" + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/0" + } }, { "httpRequest": { - "url": "https://reqres.in/api/users" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/1" } }, { "httpRequest": { - "url": "https://reqres.in/api/users/2", - "method": "put", - "request": { - "body": { - "name": "morpheus", - "job": "zion resident" - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/2" } }, { "httpRequest": { - "url": "https://reqres.in/api/users", - "method": "post", - "request": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "response": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "statusCodes": [ - 200, - 201 - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/3" } }, { "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 - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/4" } }, { "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" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/5" } }, { "httpRequest": { - "openApi": "getUserById" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/6" } }, { "httpRequest": { - "openApi": { - "name": "Reqres", - "operationId": "getUserById" - }, - "request": { - "parameters": { - "id": 123 - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/7" } }, { "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "getUserById" - }, - "request": { - "parameters": { - "id": 123 - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/8" } }, { "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "createUser", - "useExample": "both" - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/9" } }, { "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "updateUser", - "useExample": "request", - "exampleKey": "acme" - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/10" } }, { "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "updateUser", - "useExample": "request", - "exampleKey": "acme", - "headers": { - "Authorization": "Bearer $TOKEN" - } - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/11" } }, { @@ -15918,6 +3847,81 @@ }, "title": "Markup definition" }, + "astNodeMatch": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "$ref": "#/components/schemas/astNodeMatch" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, "markupActionString": { "type": "string", "enum": [ @@ -15946,18 +3950,7 @@ "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" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -15965,18 +3958,7 @@ "description": "Regular expressions that indicate that the current test is complete.", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -15984,18 +3966,7 @@ "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" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -16003,18 +3974,7 @@ "description": "Regular expressions that indicate that the ignored section of content is complete.", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -16022,18 +3982,7 @@ "description": "Regular expressions that indicate a step in a test.", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] } @@ -16159,6 +4108,79 @@ }, { "crawl": true + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": [ + "md" + ], + "markup": [ + { + "name": "bashCodeBlock", + "ast": { + "nodeType": "code", + "attributes": { + "lang": [ + "bash", + "sh" + ] + }, + "extract": { + "$1": "attributes.lang", + "$2": "value" + } + }, + "actions": [ + { + "runCode": { + "language": "$1", + "code": "$2" + } + } + ] + } + ] + } + ] + }, + { + "fileTypes": [ + { + "extends": "dita", + "extensions": [ + "dita", + "xml" + ], + "markup": [ + { + "name": "ditaCodeblock", + "ast": { + "nodeType": "element", + "attributes": { + "tagName": "codeblock", + "outputclass": [ + "bash", + "shell" + ] + }, + "extract": { + "$1": "attributes.outputclass", + "$2": "content" + } + }, + "actions": [ + { + "runShell": { + "command": "$2" + } + } + ] + } + ] + } + ] } ] } \ No newline at end of file diff --git a/common/src/schemas/output_schemas/endRecord_v3.schema.json b/common/src/schemas/output_schemas/endRecord_v3.schema.json deleted file mode 100644 index 9eb8fdd..0000000 --- a/common/src/schemas/output_schemas/endRecord_v3.schema.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "endRecord", - "description": "Stop the current recording.", - "anyOf": [ - { - "type": "boolean", - "nullable": true - } - ], - "examples": [ - true - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/find_v1.schema.json b/common/src/schemas/output_schemas/find_v1.schema.json deleted file mode 100644 index 8b0d80e..0000000 --- a/common/src/schemas/output_schemas/find_v1.schema.json +++ /dev/null @@ -1,171 +0,0 @@ -{ - "title": "find", - "type": "object", - "description": "Check if an element exists with the specified CSS selector.", - "properties": { - "action": { - "type": "string", - "const": "find" - }, - "css": { - "type": "string", - "description": "CSS selector that uniquely identified the element." - }, - "wait": { - "type": "object", - "description": "Pause before performing the next action.", - "additionalProperties": false, - "properties": { - "duration": { - "type": "number", - "description": "Seconds to wait. If `css` is set, the maximum duration to wait for the element to become available.", - "default": 10000 - } - } - }, - "matchText": { - "type": "object", - "description": "Check if an element displays the expected text.", - "additionalProperties": false, - "properties": { - "text": { - "type": "string", - "description": "Text that the element should display." - } - }, - "required": [ - "text" - ] - }, - "moveMouse": { - "type": "object", - "description": "Move the mouse to an element specified by a CSS sepector. Only runs if a test is being recorded.", - "additionalProperties": false, - "properties": { - "alignH": { - "type": "string", - "description": "Horizantal alignment of the mouse to the element.", - "enum": [ - "left", - "center", - "right" - ] - }, - "alignV": { - "type": "string", - "description": "Vertical alignment of the mouse to the element.", - "enum": [ - "left", - "center", - "right" - ] - }, - "offsetX": { - "type": "integer", - "description": "Number of pixels to offset the mouse along the X axis, relative to the element center. Positive values offset to the right. Negative values offset to the left." - }, - "offsetY": { - "type": "integer", - "description": "Number of pixels to offset the mouse along the Y axis, relative to the element center. Positive values offset to the top. Negative values offset to the bottom." - } - } - }, - "click": { - "type": "object", - "description": "Click an element specified by a CSS sepector.", - "additionalProperties": false, - "properties": { - "alignH": { - "type": "string", - "description": "Horizantal alignment of the mouse to the element.", - "enum": [ - "left", - "center", - "right" - ] - }, - "alignV": { - "type": "string", - "description": "Vertical alignment of the mouse to the element.", - "enum": [ - "left", - "center", - "right" - ] - }, - "offsetX": { - "type": "integer", - "description": "Number of pixels to offset the mouse along the X axis, relative to the element center. Positive values offset to the right. Negative values offset to the left." - }, - "offsetY": { - "type": "integer", - "description": "Number of pixels to offset the mouse along the Y axis, relative to the element center. Positive values offset to the top. Negative values offset to the bottom." - } - } - }, - "type": { - "type": "object", - "description": "Click an element specified by a CSS sepector.", - "additionalProperties": false, - "anyOf": [ - { - "required": [ - "keys" - ] - }, - { - "required": [ - "trailingSpecialKey" - ] - } - ], - "properties": { - "keys": { - "type": "string", - "description": "String of keys to enter." - }, - "trailingSpecialKey": { - "type": "string", - "description": "Special key pressed after the 'keys' value, if present. Supported values: https://github.com/puppeteer/puppeteer/blob/main/src/common/USKeyboardLayout.ts" - }, - "env": { - "type": "string", - "description": "Path to a `.env` file to load before performing the action." - } - } - } - }, - "required": [ - "action", - "css" - ], - "additionalProperties": false, - "examples": [ - { - "action": "find", - "css": "[title=Search]" - }, - { - "action": "find", - "css": "[title=Search]", - "wait": { - "duration": 10000 - }, - "matchText": { - "text": "Search" - }, - "moveMouse": { - "alignH": "center", - "alignV": "center", - "offsetX": 0, - "offsetY": 0 - }, - "click": {}, - "type": { - "keys": "$SHORTHAIR_CAT_SEARCH", - "trailingSpecialKey": "Enter", - "env": "./sample/variables.env" - } - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/goTo_v1.schema.json b/common/src/schemas/output_schemas/goTo_v1.schema.json deleted file mode 100644 index 030a406..0000000 --- a/common/src/schemas/output_schemas/goTo_v1.schema.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "title": "goTo", - "type": "object", - "description": "Navigate to a specified URI.", - "properties": { - "action": { - "type": "string", - "const": "goTo" - }, - "uri": { - "type": "string", - "description": "URI to navigate to." - } - }, - "required": [ - "action", - "uri" - ], - "additionalProperties": false, - "examples": [ - { - "action": "goTo", - "uri": "https://www.google.com" - }, - { - "action": "goTo", - "uri": "$URI" - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/httpRequest_v1.schema.json b/common/src/schemas/output_schemas/httpRequest_v1.schema.json deleted file mode 100644 index 0d9a1fd..0000000 --- a/common/src/schemas/output_schemas/httpRequest_v1.schema.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "title": "httpRequest", - "type": "object", - "description": "Perform a generic HTTP request, for example to a REST API.", - "properties": { - "action": { - "type": "string", - "const": "httpRequest" - }, - "uri": { - "type": "string", - "description": "The URI for the HTTP request." - }, - "statusCodes": { - "type": "array", - "items": { - "type": "integer" - }, - "default": [ - 200 - ] - }, - "env": { - "type": "string", - "description": "" - }, - "method": { - "type": "string", - "description": "Method of the HTTP request", - "enum": [ - "get", - "post", - "patch", - "delete" - ], - "default": "get" - }, - "requestHeaders": { - "description": "Headers to include in the HTTP request, in key/value format.", - "type": "object", - "additionalProperties": true, - "minProperties": 1, - "properties": {} - }, - "responseHeaders": { - "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the action fails.", - "type": "object", - "additionalProperties": true, - "minProperties": 1, - "properties": {} - }, - "requestParams": { - "description": "URL parameters to include in the HTTP request, in key/value format.", - "type": "object", - "additionalProperties": true, - "minProperties": 1, - "properties": {} - }, - "responseParams": { - "description": "URL parameters expected in the response, in key/value format. If one or more `responseParams` entries aren't present in the response, the action fails.", - "type": "object", - "additionalProperties": true, - "minProperties": 1, - "properties": {} - }, - "requestData": { - "type": "object", - "additionalProperties": true, - "minProperties": 1, - "properties": {} - }, - "responseData": { - "type": "object", - "additionalProperties": true, - "minProperties": 1, - "properties": {} - } - }, - "required": [ - "action", - "uri" - ], - "additionalProperties": false, - "examples": [ - { - "action": "httpRequest", - "uri": "https://www.api-server.com", - "method": "post" - }, - { - "action": "httpRequest", - "env": "path/to/variables.env", - "uri": "https://www.api-server.com", - "method": "post", - "requestHeaders": { - "header": "value" - }, - "requestParams": { - "param": "value" - }, - "requestData": { - "field": "value" - }, - "responseHeaders": { - "header": "value" - }, - "responseData": { - "field": "value" - }, - "statusCodes": [ - 200 - ] - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/matchText_v1.schema.json b/common/src/schemas/output_schemas/matchText_v1.schema.json deleted file mode 100644 index b8733a2..0000000 --- a/common/src/schemas/output_schemas/matchText_v1.schema.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "title": "matchText", - "type": "object", - "description": "Check if an element displays the expected text.", - "properties": { - "action": { - "type": "string", - "const": "matchText" - }, - "css": { - "type": "string", - "description": "CSS selector that uniquely identified the element." - }, - "text": { - "type": "string", - "description": "Text that the element should display." - } - }, - "required": [ - "action", - "css", - "text" - ], - "additionalProperties": false, - "examples": [ - { - "action": "matchText", - "css": "#gbqfbb", - "text": "I'm Feeling Lucky" - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/moveMouse_v1.schema.json b/common/src/schemas/output_schemas/moveMouse_v1.schema.json deleted file mode 100644 index ab2e73c..0000000 --- a/common/src/schemas/output_schemas/moveMouse_v1.schema.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "title": "moveMouse", - "type": "object", - "description": "Move the mouse to an element specified by a CSS sepector. Only runs if a test is being recorded.", - "properties": { - "action": { - "type": "string", - "const": "moveMouse" - }, - "css": { - "type": "string", - "description": "CSS selector that uniquely identified the element." - }, - "alignH": { - "type": "string", - "description": "Horizantal alignment of the mouse to the element.", - "enum": [ - "left", - "center", - "right" - ] - }, - "alignV": { - "type": "string", - "description": "Vertical alignment of the mouse to the element.", - "enum": [ - "left", - "center", - "right" - ] - }, - "offsetX": { - "type": "integer", - "description": "Number of pixels to offset the mouse along the X axis, relative to the element center. Positive values offset to the right. Negative values offset to the left." - }, - "offsetY": { - "type": "integer", - "description": "Number of pixels to offset the mouse along the Y axis, relative to the element center. Positive values offset to the top. Negative values offset to the bottom." - } - }, - "required": [ - "action", - "css" - ], - "additionalProperties": false, - "examples": [ - { - "action": "moveMouse", - "css": "[title=Search]" - }, - { - "action": "moveMouse", - "css": "[title=Search]", - "alignH": "center", - "alignV": "center", - "offsetX": 10, - "offsetY": 10 - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/resolvedTests_v3.schema.json b/common/src/schemas/output_schemas/resolvedTests_v3.schema.json deleted file mode 100644 index a0f89f7..0000000 --- a/common/src/schemas/output_schemas/resolvedTests_v3.schema.json +++ /dev/null @@ -1,32829 +0,0 @@ -{ - "$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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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" - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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 - } - ] - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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": [] - } - ] - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/runShell_v1.schema.json b/common/src/schemas/output_schemas/runShell_v1.schema.json deleted file mode 100644 index b1c349c..0000000 --- a/common/src/schemas/output_schemas/runShell_v1.schema.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "title": "runShell", - "type": "object", - "description": "Perform a native shell command.", - "properties": { - "action": { - "type": "string", - "const": "runShell" - }, - "command": { - "type": "string", - "description": "Command to perform in the machine's default shell." - }, - "env": { - "type": "string", - "description": "Path to a `.env` file to load before performing the action." - } - }, - "additionalProperties": false, - "required": [ - "action", - "command" - ], - "examples": [ - { - "action": "runShell", - "command": "echo $username" - }, - { - "action": "runShell", - "command": "echo $username", - "env": "./variables.env" - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/screenshot_v1.schema.json b/common/src/schemas/output_schemas/screenshot_v1.schema.json deleted file mode 100644 index 781fc0a..0000000 --- a/common/src/schemas/output_schemas/screenshot_v1.schema.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "title": "screenshot", - "type": "object", - "description": "Navigate to a specified URI.", - "properties": { - "action": { - "type": "string", - "const": "screenshot" - }, - "mediaDirectory": { - "type": "string", - "description": "The directory path for media created by the action. Overrides the default directory config. Default is config.imageDirectory or config.videoDirectory depending on the file type." - }, - "filename": { - "type": "string", - "description": "Name of the media file. If not specified, the filename is randomized." - }, - "matchPrevious": { - "type": "boolean", - "description": "If `true`, performs a pixel-diff against an image that matches the path of the new screenshot. If a previous image doesn't exist at the path, this option is ignored.", - "default": false - }, - "matchThreshold": { - "type": "number", - "description": "Decimal value of percentage of pixels that must be different between the old and new screenshots to fail the action. For example, a value of `0.3` fails the action if the diff is 30% or more of pixels.", - "default": 0.3, - "exclusiveMinimum": 0, - "maximum": 1 - } - }, - "required": [ - "action" - ], - "additionalProperties": false, - "examples": [ - { - "action": "screenshot", - "filename": "results.png" - }, - { - "action": "screenshot", - "mediaDirectory": "samples", - "filename": "results.png", - "matchPrevious": true, - "matchThreshold": 0.3 - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/scroll_v1.schema.json b/common/src/schemas/output_schemas/scroll_v1.schema.json deleted file mode 100644 index fa24af9..0000000 --- a/common/src/schemas/output_schemas/scroll_v1.schema.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "title": "scroll", - "type": "object", - "description": "Scroll the page by the specified number of pixels. Only runs if a test is being recorded.", - "anyOf": [ - { - "required": [ - "x" - ] - }, - { - "required": [ - "y" - ] - } - ], - "properties": { - "action": { - "type": "string", - "const": "scroll" - }, - "x": { - "type": "integer", - "description": "Number of pixels to scroll along the X axis. Positive values scroll to the right. Negative values scroll to the left." - }, - "y": { - "type": "integer", - "description": "Number of pixels to scroll along the Y axis. Positive values scroll to the top. Negative values scroll to the bottom." - } - }, - "required": [ - "action" - ], - "additionalProperties": false, - "examples": [ - { - "action": "scroll", - "x": 100 - }, - { - "action": "scroll", - "y": 100 - }, - { - "action": "scroll", - "x": 100, - "y": 100 - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/startRecording_v1.schema.json b/common/src/schemas/output_schemas/startRecording_v1.schema.json deleted file mode 100644 index 85e0cad..0000000 --- a/common/src/schemas/output_schemas/startRecording_v1.schema.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "title": "startRecording", - "type": "object", - "description": "Start recording the current browser viewport. Must be followed by a `stopeRecording` action. Supported extensions: [ '.mp4', '.webm', '.gif' ]", - "properties": { - "action": { - "type": "string", - "const": "startRecording" - }, - "overwrite": { - "type": "boolean", - "description": "If `true`, overwrites files at the specified path. If `false`, skips the action if a file exists at the specified path.", - "default": false - }, - "mediaDirectory": { - "type": "string", - "description": "The directory path for media created by the action. Overrides the default directory config. Default is config.imageDirectory or config.videoDirectory depending on the file type." - }, - "filename": { - "type": "string", - "description": "Name of the media file. If not specified, the filename is randomized." - }, - "fps": { - "type": "integer", - "description": "Target frames-per-second for the recording.", - "default": 30 - }, - "width": { - "type": "integer", - "description": "Target width of the recording. Defaults to the browser window width." - }, - "height": { - "type": "integer", - "description": "Target height of the recording. Defaults to the browser window height." - } - }, - "required": [ - "action" - ], - "additionalProperties": false, - "examples": [ - { - "action": "startRecording" - }, - { - "action": "startRecording", - "overwrite": false, - "mediaDirectory": "./samples", - "filename": "results.mp4", - "fps": 30, - "width": 1200, - "height": 800 - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/stopRecording_v1.schema.json b/common/src/schemas/output_schemas/stopRecording_v1.schema.json deleted file mode 100644 index b368fd9..0000000 --- a/common/src/schemas/output_schemas/stopRecording_v1.schema.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "title": "stopRecording", - "type": "object", - "description": "Stop recording the current browser viewport.", - "properties": { - "action": { - "type": "string", - "const": "stopRecording" - } - }, - "additionalProperties": false, - "required": [ - "action" - ], - "examples": [ - { - "action": "stopRecording" - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/type_v1.schema.json b/common/src/schemas/output_schemas/type_v1.schema.json deleted file mode 100644 index 6c7c819..0000000 --- a/common/src/schemas/output_schemas/type_v1.schema.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "title": "type", - "type": "object", - "description": "Click an element specified by a CSS sepector.", - "anyOf": [ - { - "required": [ - "keys" - ] - }, - { - "required": [ - "trailingSpecialKey" - ] - } - ], - "properties": { - "action": { - "type": "string", - "const": "type" - }, - "css": { - "type": "string", - "description": "CSS selector that uniquely identified the element." - }, - "keys": { - "type": "string", - "description": "String of keys to enter." - }, - "trailingSpecialKey": { - "type": "string", - "description": "Special key pressed after the 'keys' value, if present. Supported values: https://github.com/puppeteer/puppeteer/blob/main/src/common/USKeyboardLayout.ts" - }, - "env": { - "type": "string", - "description": "Path to a `.env` file to load before performing the action." - } - }, - "required": [ - "action", - "css" - ], - "additionalProperties": false, - "examples": [ - { - "action": "type", - "css": "[title=Search]", - "keys": "kittens" - }, - { - "action": "type", - "css": "[title=Search]", - "trailingSpecialKey": "Enter" - }, - { - "action": "type", - "css": "[title=Search]", - "keys": "kittens", - "trailingSpecialKey": "Enter" - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/output_schemas/wait_v1.schema.json b/common/src/schemas/output_schemas/wait_v1.schema.json deleted file mode 100644 index 9bb7c6b..0000000 --- a/common/src/schemas/output_schemas/wait_v1.schema.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "title": "wait", - "type": "object", - "description": "Pause before performing the next action.", - "properties": { - "action": { - "type": "string", - "const": "wait" - }, - "css": { - "type": "string", - "description": "CSS selector that uniquely identified the element to find." - }, - "duration": { - "type": "number", - "description": "Seconds to wait. If `css` is set, the maximum duration to wait for the element to become available.", - "default": 10000 - } - }, - "required": [ - "action" - ], - "additionalProperties": false, - "examples": [ - { - "action": "wait" - }, - { - "action": "wait", - "css": "[title=Search]" - }, - { - "action": "wait", - "duration": 5000 - }, - { - "action": "wait", - "css": "[title=Search]", - "duration": 5000 - } - ] -} \ No newline at end of file diff --git a/common/src/schemas/schemas.json b/common/src/schemas/schemas.json index 6cfab64..3c8b70d 100644 --- a/common/src/schemas/schemas.json +++ b/common/src/schemas/schemas.json @@ -427,18 +427,7 @@ "default": ".", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, @@ -571,22 +560,12 @@ "description": "Platforms to run tests on.", "anyOf": [ { - "type": "string", - "enum": [ - "linux", - "mac", - "windows" - ] + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" }, { "type": "array", "items": { - "type": "string", - "enum": [ - "linux", - "mac", - "windows" - ] + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" } } ] @@ -595,148 +574,20 @@ "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." + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browserName" }, { - "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" + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browserName" }, { - "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" + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browser" } ] } @@ -774,15 +625,7 @@ "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." + "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/browserName" }, "headless": { "type": "boolean", @@ -982,52542 +825,7892 @@ "description": "File extensions to use with type.", "anyOf": [ { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/components/schemas/stringOrArray" } ] }, "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.", + "$ref": "#/components/schemas/inlineStatements" + }, + "markup": { + "description": "Markup definitions for the file type.", + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/components/schemas/markupDefinition" + } + } + } + }, + { + "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": [ + { + "$ref": "#/components/schemas/stringOrArray" + } + ] + }, + "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": [ { - "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": [ + "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/string" + }, { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/object" } - ] - }, - "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" + ], + "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)" + } } - ] - }, - "step": { - "description": "Regular expressions that indicate a step in a test.", - "anyOf": [ + }, + "examples": [ + "docker run hello-world", { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } + "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": "Inline statement definition" + ] + } + } + } + ] + } + } + ] + }, + "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" + ] }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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" - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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 - } - ] - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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" - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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 - } - ] - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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." - } - ] - } - } - } - ] - } - }, - "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" - } - ] - }, + { + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." + }, + "descriptionPath": { + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/descriptionPath" + }, + "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": { + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" + }, + "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" + } + }, + "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": { + "$ref": "#/components/schemas/environment" + }, + "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", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "$ref": "#/components/schemas/astNodeMatch" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "$ref": "#/components/schemas/stringOrArray" + } + ] + }, + "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": [ + { + "$ref": "#/components/schemas/markupActionString" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/markupActionString" + }, + { + "$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": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/$schema" + }, + "stepId": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/stepId" + }, + "description": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/description" + }, + "unsafe": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/unsafe" + }, + "outputs": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/outputs" + }, + "variables": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/variables" + }, + "breakpoint": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/breakpoint" + } + }, + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "checkLink" + ], + "properties": { + "checkLink": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "checkLink", + "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": [ - "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" - } - ] + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/components/schemas/string" }, { - "allOf": [ - { - "type": "object", - "dynamicDefaults": { - "stepId": "uuid" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/components/schemas/object" + } + ], + "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" + ] }, - "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 - } + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] }, - "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 + "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" + } + ] } - ], - "examples": [ - true - ] - } - }, - "title": "stopRecord" + } + ], + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "click" + ], + "properties": { + "click": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "click", + "description": "Click or tap an element.", + "anyOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/string" }, { - "allOf": [ - { - "type": "object", - "dynamicDefaults": { - "stepId": "uuid" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/object" + }, + { + "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" + ] }, - "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." - } + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "button": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" + }, + "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" }, - "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." + { + "type": "array", + "items": { + "type": "string" } - }, - "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 - } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." }, - "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" + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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" }, { - "allOf": [ - { - "type": "object", - "dynamicDefaults": { - "stepId": "uuid" + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } + ] + } + }, + "title": "click" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/string" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/object" + } + ], + "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" + ] }, - "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 - } + { + "required": [ + "elementText" + ] }, - "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 - } - } - } - ] + { + "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" }, - "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 - } - } - } - ] + { + "type": "number" }, - "duration": { - "type": "integer", - "description": "Duration of the drag operation in milliseconds.", - "default": 1000, - "minimum": 0 + { + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click" + }, + { + "type": "object", + "properties": { + "button": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" + } + }, + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type" + }, + { + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "goTo" + ], + "properties": { + "goTo": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "goTo", + "anyOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/string" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/object" + } + ], + "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 }, - "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 - } - } - } + "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" ] }, - "string": { - "title": "Element (simple)", + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } + ], + "properties": { + "selector": { "type": "string", - "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." + "description": "CSS selector for the element to wait for." }, - "object": { - "title": "Element (detailed)", - "type": "object", + "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": [ { - "required": [ - "selector" - ] - }, - { - "required": [ - "elementText" - ] - }, - { - "required": [ - "elementId" - ] - }, - { - "required": [ - "elementTestId" - ] - }, - { - "required": [ - "elementClass" - ] - }, - { - "required": [ - "elementAttribute" - ] + "type": "string" }, { - "required": [ - "elementAria" - ] + "type": "array", + "items": { + "type": "string" + } } ], - "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" - } - ] + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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.*/" + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" }, { - "allOf": [ - { - "type": "object", - "dynamicDefaults": { - "stepId": "uuid" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/object" + } + ], + "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" + ] }, - "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 - } + { + "required": [ + "openApi" + ] + } + ], + "additionalProperties": false, + "properties": { + "url": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" }, - "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" - ] - } + "openApi": { + "anyOf": [ + { + "allOf": [ + { + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" }, - "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" - ] + { + "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": [ + { + "$ref": "#/properties/integrations/properties/openApi/items/allOf/0" }, - "object": { + { "type": "object", - "additionalProperties": false, "required": [ - "name" - ], - "anyOf": [ - { - "required": [ - "path" - ], - "not": { - "required": [ - "variable" - ] - } - }, - { - "required": [ - "variable" - ], - "not": { - "anyOf": [ - { - "required": [ - "path" - ] - }, - { - "required": [ - "directory" - ] - } - ] - } - } + "operationId" ], - "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)" + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "runShell" + ], + "properties": { + "runShell": { + "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0" + } + }, + "title": "runShell" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "runCode" + ], + "properties": { + "runCode": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "runCode", + "description": "Assemble and run code.", + "anyOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/6/allOf/1/properties/runCode/components/schemas/object" + } + ], + "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" } - }, - "examples": [ - "session_token", - "./test-data/auth-session.txt", - "test_env_cookie", + ] + }, + "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": [ { - "name": "auth_cookie", - "variable": "AUTH_COOKIE" - }, + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/object" + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ { - "name": "test_cookie", - "path": "test-cookie.txt" + "type": "string" + } + ] + } + } + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", + "properties": { + "keys": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" + }, + "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" }, { - "name": "session_token", - "path": "session-token.txt", - "directory": "./test-data" + "type": "number" }, { - "name": "user_session", - "path": "saved-cookies.txt", - "domain": "app.example.com" + "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$" ] }, { - "allOf": [ - { - "type": "object", - "dynamicDefaults": { - "stepId": "uuid" + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 + } + ] + } + }, + "title": "type" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/path" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/object" + }, + { + "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": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/path" }, - "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." - } + "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": "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." - } + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/crop_element" + } + ] + } + }, + "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" }, - "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 - } + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." }, - "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, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { "anyOf": [ { - "type": "number", - "title": "Wait (simple)" + "type": "string" }, { - "title": "Wait (environment variable)", - "type": "string", - "pattern": "(\\$[A-Za-z0-9_]+)", - "transform": [ - "trim" - ] + "type": "number" }, - { - "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 + { + "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 + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/padding" + } + ] } } - ] - } - ], - "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" + "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." } - }, - { - "stopRecord": true - }, - { - "screenshot": true - }, - { - "screenshot": "image.png" - }, + } + }, + "examples": [ + true, + "image.png", + "static/images/image.png", + "/User/manny/projects/doc-detective/static/images/image.png", { - "screenshot": "static/images/image.png" + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" }, { - "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" }, { - "screenshot": { - "path": "image.png", - "directory": "static/images", - "maxVariation": 0.1, - "overwrite": "aboveVariation", - "crop": "#elementToScreenshot" + "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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ { - "screenshot": { - "path": "image.png", - "directory": "static/images", - "maxVariation": 0.1, - "overwrite": "aboveVariation" - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/components/schemas/string" }, { - "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 + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/components/schemas/object" + } + ], + "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" + ] + } + ] + } } - } - } - }, - { - "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" + ], + "title": "Save cookie (detailed)" } - }, - { - "find": "Find me!" - }, + } + }, + "examples": [ + "session_token", + "test_env_cookie", { - "find": { - "selector": "[title=Search]" - } + "name": "auth_cookie", + "path": "auth-cookie.txt" }, { - "find": { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": "shorthair cat" - } + "name": "session_token", + "variable": "SESSION_TOKEN" }, { - "find": { - "selector": "[title=Search]", - "click": { - "button": "right" - } - } + "name": "test_cookie", + "path": "test-cookie.txt", + "overwrite": true }, { - "find": { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": { - "keys": [ - "shorthair cat" - ], - "inputDelay": 100 - } - } + "name": "user_session", + "path": "user-session.txt", + "directory": "./test-data", + "overwrite": true }, { - "click": true - }, + "name": "login_token", + "path": "login-token.txt", + "domain": "app.example.com" + } + ] + } + }, + "title": "saveCookie" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ { - "click": "right" + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/components/schemas/string" }, { - "click": { - "button": "left", - "elementText": "Element text" - } + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/components/schemas/object" }, { - "click": { - "selector": "#elementToScreenshot", - "elementText": "Element text", - "button": "middle" + "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", { - "httpRequest": "https://reqres.in/api/users" - }, + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" + } + ] + } + }, + "title": "record" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "type": "object", + "required": [ + "stopRecord" + ], + "properties": { + "stopRecord": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "stopRecord", + "description": "Stop the current recording.", + "anyOf": [ { - "httpRequest": { - "url": "https://reqres.in/api/users" - } + "type": "boolean", + "nullable": true + } + ], + "examples": [ + true + ] + } + }, + "title": "stopRecord" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + { + "title": "loadVariables", + "type": "object", + "required": [ + "loadVariables" + ], + "properties": { + "loadVariables": { + "$ref": "#/properties/loadVariables" + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", + "description": "The element to drag." }, - { - "httpRequest": { - "url": "https://reqres.in/api/users/2", - "method": "put", - "request": { - "body": { - "name": "morpheus", - "job": "zion resident" - } - } - } + "target": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", + "description": "The target location to drop the element." }, - { - "httpRequest": { - "url": "https://reqres.in/api/users", - "method": "post", - "request": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "response": { - "body": { - "name": "morpheus", - "job": "leader" + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/string" + }, + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/object" } - }, - "statusCodes": [ - 200, - 201 ] - } - }, - { - "httpRequest": { - "url": "https://www.api-server.com", - "method": "post", - "timeout": 30000, - "request": { - "body": { - "field": "value" + }, + "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" + ] }, - "headers": { - "header": "value" + { + "required": [ + "elementText" + ] }, - "parameters": { - "param": "value" + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] } - }, - "response": { - "body": { - "field": "value" + ], + "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." }, - "headers": { - "header": "value" + "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 } - }, - "statusCodes": [ - 200 - ] + } } + } + }, + "examples": [ + { + "source": "Table", + "target": "#canvas" }, { - "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" + "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 } }, { - "httpRequest": { - "openApi": "getUserById" - } + "source": "/Widget Item.*/", + "target": "#canvas" }, { - "httpRequest": { - "openApi": { - "name": "Reqres", - "operationId": "getUserById" - }, - "request": { - "parameters": { - "id": 123 - } - } + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" + }, + "target": { + "elementText": "/Drop Zone.*/" } + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/components/schemas/string" }, { - "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "getUserById" - }, - "request": { - "parameters": { - "id": 123 + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/components/schemas/object" + } + ], + "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", { - "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "createUser", - "useExample": "both" - } - } + "name": "auth_cookie", + "variable": "AUTH_COOKIE" }, { - "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "updateUser", - "useExample": "request", - "exampleKey": "acme" - } - } + "name": "test_cookie", + "path": "test-cookie.txt" }, { - "httpRequest": { - "openApi": { - "descriptionPath": "https://api.example.com/openapi.json", - "operationId": "updateUser", - "useExample": "request", - "exampleKey": "acme", - "headers": { - "Authorization": "Bearer $TOKEN" - } - } - } + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" }, { - "stepId": "breakpoint-example", - "description": "Step with breakpoint enabled", - "goTo": "https://www.example.com", - "breakpoint": true + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" + } + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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)" }, { - "checkLink": "https://www.google.com", - "breakpoint": false + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/15/allOf/1/properties/wait/components/schemas/string" }, { - "dragAndDrop": { - "source": { - "selector": "#sourceElement" - }, - "target": { - "selector": "#targetElement" - } + "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": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/0" + } + }, + { + "find": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/1" + } + }, + { + "find": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/2" + } + }, + { + "find": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/3" + } + }, + { + "find": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/4" + } + }, + { + "click": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/0" + } + }, + { + "click": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/1" + } + }, + { + "click": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/2" + } + }, + { + "click": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/3" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/0" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/1" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/2" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/3" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/4" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/5" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/6" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/7" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/8" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/9" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/10" + } + }, + { + "httpRequest": { + "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/11" + } + }, + { + "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" + }, + "astNodeMatch": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "$ref": "#/components/schemas/astNodeMatch" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "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": [ + { + "$ref": "#/components/schemas/stringOrArray" + } + ] + }, + "testEnd": { + "description": "Regular expressions that indicate that the current test is complete.", + "anyOf": [ + { + "$ref": "#/components/schemas/stringOrArray" + } + ] + }, + "ignoreStart": { + "description": "Regular expressions that indicates that the following content should be ignored for testing purposes.", + "anyOf": [ + { + "$ref": "#/components/schemas/stringOrArray" + } + ] + }, + "ignoreEnd": { + "description": "Regular expressions that indicate that the ignored section of content is complete.", + "anyOf": [ + { + "$ref": "#/components/schemas/stringOrArray" + } + ] + }, + "step": { + "description": "Regular expressions that indicate a step in a test.", + "anyOf": [ + { + "$ref": "#/components/schemas/stringOrArray" + } + ] + } + }, + "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 + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": [ + "md" + ], + "markup": [ + { + "name": "bashCodeBlock", + "ast": { + "nodeType": "code", + "attributes": { + "lang": [ + "bash", + "sh" + ] + }, + "extract": { + "$1": "attributes.lang", + "$2": "value" + } + }, + "actions": [ + { + "runCode": { + "language": "$1", + "code": "$2" + } + } + ] + } + ] + } + ] + }, + { + "fileTypes": [ + { + "extends": "dita", + "extensions": [ + "dita", + "xml" + ], + "markup": [ + { + "name": "ditaCodeblock", + "ast": { + "nodeType": "element", + "attributes": { + "tagName": "codeblock", + "outputclass": [ + "bash", + "shell" + ] + }, + "extract": { + "$1": "attributes.outputclass", + "$2": "content" + } + }, + "actions": [ + { + "runShell": { + "command": "$2" + } + } + ] + } + ] + } + ] + } + ] + }, + "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" }, - "title": "Resolved context" + { + "type": "number" + }, + { + "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." }, - "dynamicDefaults": { - "testId": "uuid" + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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": [ - "steps" + "selector" ] }, { "required": [ - "contexts" + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" ] } ], - "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)" - } - ] + "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" }, - "examples": [ - { - "steps": [ + { + "type": "array", + "items": { + "anyOf": [ { - "checkLink": "https://www.duckduckgo.com" + "type": "string" } ] - }, - { - "steps": [ - { - "goTo": { - "url": "https://www.duckduckgo.com" - } - }, - { - "find": { - "selector": "[title=Search]", - "click": true, - "type": { - "keys": [ - "shorthair cats", - "$ENTER$" - ] + } + } + ] + }, + { + "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" } - } + ] } - ] - }, - { - "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": {} - } + } + ] + }, + "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" } - ], - "steps": [ - { - "loadVariables": ".env" - }, - { - "runShell": { - "command": "echo", - "args": [ - "$USER" - ], - "maxVariation": 0, - "overwrite": "aboveVariation" - }, - "variables": {} - }, + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ { - "checkLink": { - "url": "https://www.duckduckgo.com" - } + "type": "string" }, { - "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": {} + "type": "number" }, { - "goTo": { - "url": "https://www.duckduckgo.com" + "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": [ { - "find": { - "selector": "[title=Search]", - "elementText": "Search", - "timeout": 10000, - "moveTo": true, - "click": true, - "type": { - "keys": [ - "shorthair cat" - ] - } - }, - "variables": {} + "type": "string" }, { - "type": { - "keys": [ - "$ENTER$" + "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" }, { - "screenshot": { - "maxVariation": 0, - "overwrite": "aboveVariation" + "type": "array", + "items": { + "type": "string" } } ], - "detectSteps": true + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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" }, { - "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": "number" + }, + { + "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": [ - "tests" - ], - "examples": [ + "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": [ { - "tests": [ + "allOf": [ { - "steps": [ - { - "checkLink": { - "url": "https://www.duckduckgo.com" - } - } - ] + "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." } ] }, { - "specId": "Do all the things! - Spec", - "runOn": [ - { - "platforms": [ - "windows", - "mac" - ], - "browsers": { - "name": "firefox", - "window": {}, - "viewport": {} - } - } - ], - "tests": [ + "allOf": [ { - "testId": "Do all the things! - Test", - "description": "This test includes nearly every property across all actions.", - "runOn": [ + "version": "1.0.0", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openApi", + "type": "object", + "description": "OpenAPI description and configuration.", + "additionalProperties": false, + "anyOf": [ { - "platforms": "linux", - "browsers": "firefox" + "required": [ + "descriptionPath" + ] + }, + { + "required": [ + "operationId" + ] } ], - "steps": [ + "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": [ { - "loadVariables": ".env" + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" }, { - "runShell": { - "command": "echo", - "args": [ - "$USER" - ], - "maxVariation": 0, - "overwrite": "aboveVariation" - }, - "variables": {} + "name": "Reqres", + "operationId": "getUserById" }, { - "checkLink": { - "url": "https://www.duckduckgo.com" - } + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" }, { - "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": {} + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" }, { - "goTo": { - "url": "https://www.duckduckgo.com" - } + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1" }, { - "find": { - "selector": "[title=Search]", - "elementText": "Search", - "timeout": 10000, - "moveTo": true, - "click": true, - "type": { - "keys": [ - "shorthair cat" - ] - } - }, - "variables": {} + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201 }, { - "type": { - "keys": [ - "$ENTER$" - ] - } + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both", + "exampleKey": "example1", + "statusCode": 201, + "validateAgainstSchema": "none" }, { - "screenshot": { - "maxVariation": 0, - "overwrite": "aboveVariation" + "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" ], - "detectSteps": true + "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" } ] }, - { - "specId": "Make a request from an OpenAPI definition", - "openApi": [ + "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": [ { - "descriptionPath": "https://www.acme.com/openapi.json", - "server": "https://api.acme.com", - "name": "Acme" + "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" } ], - "tests": [ + "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": [ { - "steps": [ - { - "httpRequest": { - "openApi": { - "operationId": "getUserById", - "validateAgainstSchema": "both", - "useExample": "none", - "exampleKey": "" - }, - "request": { - "parameters": { - "id": 123 - } - }, - "response": {}, - "maxVariation": 0, - "overwrite": "aboveVariation" - }, - "variables": {} - } - ] + "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." + } } }, - "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": [] + "overwrite": { + "type": "string", + "description": "If `true`, overwrites the existing recording at `path` if it exists.", + "enum": [ + "true", + "false" + ] } - ], - "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": [] - } - ] + "title": "Record (detailed)" + } + } + }, + "examples": [ + true, + "results.mp4", + { + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" } ] }, From 70abaaf13b28eefac1716486512470fcc9d0438f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:05:07 +0000 Subject: [PATCH 5/6] Fix schema dereferencing for recursive AST schemas - Use full dereferencing and handle circular refs with custom clone function - The breakCircularRefs function preserves schema structure while breaking cycles - Both config_v3 and resolvedTests_v3 schemas are now handled correctly - All 306 common tests and 43 resolver tests pass Co-authored-by: hawkeyexl <5209367+hawkeyexl@users.noreply.github.com> --- common/dist/schemas/config_v3.schema.json | 12927 +++- .../dist/schemas/resolvedTests_v3.schema.json | 33187 +++++++++- common/src/schemas/dereferenceSchemas.js | 57 +- .../output_schemas/config_v3.schema.json | 12927 +++- .../resolvedTests_v3.schema.json | 33172 ++++++++++ common/src/schemas/schemas.json | 52263 +++++++++++++++- 6 files changed, 138010 insertions(+), 6523 deletions(-) create mode 100644 common/src/schemas/output_schemas/resolvedTests_v3.schema.json diff --git a/common/dist/schemas/config_v3.schema.json b/common/dist/schemas/config_v3.schema.json index d408b02..c1d8b30 100644 --- a/common/dist/schemas/config_v3.schema.json +++ b/common/dist/schemas/config_v3.schema.json @@ -29,7 +29,18 @@ "default": ".", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -162,12 +173,22 @@ "description": "Platforms to run tests on.", "anyOf": [ { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] }, { "type": "array", "items": { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] } } ] @@ -176,20 +197,148 @@ "description": "Browsers to run tests on.", "anyOf": [ { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." }, { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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" }, { "type": "array", "items": { "anyOf": [ { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." }, { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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" } ] } @@ -227,7 +376,15 @@ "additionalProperties": false, "properties": { "name": { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." }, "headless": { "type": "boolean", @@ -427,144 +584,7744 @@ "description": "File extensions to use with type.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, "inlineStatements": { - "$ref": "#/components/schemas/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": { - "$ref": "#/components/schemas/markupDefinition" - } - } - } - }, - { - "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": [ - { - "$ref": "#/components/schemas/stringOrArray" - } - ] - }, - "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": [ - { - "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/string" - }, - { - "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/object" - } - ], - "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." + "type": "object", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" }, - "args": { + { "type": "array", - "description": "Arguments for the command.", "items": { - "anyOf": [ - { - "type": "string" - } - ] + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "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" - } - ] + { + "type": "boolean" }, - "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`." + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" }, - "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." + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} }, - "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 + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" }, - "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" + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" }, - "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 + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } } - }, - "title": "Run shell command (detailed)" + ] } - } + ] + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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", @@ -661,7 +8418,8 @@ "description": "Name of the OpenAPI description, as defined in your configuration." }, "descriptionPath": { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/descriptionPath" + "type": "string", + "description": "URL or local path to the OpenAPI description." }, "definition": { "type": "object", @@ -671,7 +8429,8 @@ "title": "OpenAPI definition" }, "operationId": { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" + "type": "string", + "description": "ID of the operation to use for the request." }, "server": { "type": "string", @@ -863,7 +8622,39 @@ } }, "environment": { - "$ref": "#/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" }, "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.", @@ -939,13 +8730,104 @@ }, "ast": { "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", - "$ref": "#/components/schemas/astNodeMatch" + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} + }, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" }, "regex": { "description": "Regular expressions to match the markup type.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -958,14 +8840,48 @@ "description": "Actions to perform when the markup type is detected.", "anyOf": [ { - "$ref": "#/components/schemas/markupActionString" + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] }, { "type": "array", "items": { "anyOf": [ { - "$ref": "#/components/schemas/markupActionString" + "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#", @@ -981,25 +8897,53 @@ }, "properties": { "$schema": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/$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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/stepId" + "type": "string", + "description": "ID of the step." }, "description": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/description" + "type": "string", + "description": "Description of the step." }, "unsafe": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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" @@ -1059,7 +9003,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -1072,10 +9071,64 @@ "title": "checkLink", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/components/schemas/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 + ] + } + } } ], "components": { @@ -1166,7 +9219,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -1180,10 +9288,112 @@ "description": "Click or tap an element.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/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." }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/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." + } + } }, { "type": "boolean" @@ -1247,7 +9457,13 @@ ], "properties": { "button": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] }, "elementText": { "type": "string", @@ -1275,76 +9491,771 @@ "items": { "type": "string" } - } - ], - "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." - }, - "elementAttribute": { - "type": "object", - "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", - "additionalProperties": { - "anyOf": [ + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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$" + ], { - "type": "string" + "keys": "kittens" }, { - "type": "number" + "keys": [ + "$ENTER$" + ] }, { - "type": "boolean" + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 } ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } } - }, - "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": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/string" - }, - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/object" - } ], "components": { "schemas": { @@ -1460,13 +10371,268 @@ "description": "Click the element.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/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" + } + ] }, { "type": "object", "properties": { "button": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] } }, "title": "Find element and click" @@ -1477,7 +10643,248 @@ "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": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/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 + } + ] }, { "not": { @@ -1545,17 +10952,72 @@ "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": "find" - } - ] - }, - { - "allOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + "title": "Common" }, { "type": "object", @@ -1568,10 +11030,173 @@ "title": "goTo", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/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)" } ], "components": { @@ -1827,7 +11452,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -1841,10 +11521,400 @@ "description": "Perform a generic HTTP request, for example to an API.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/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" + } + } } ], "components": { @@ -1876,14 +11946,21 @@ "additionalProperties": false, "properties": { "url": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/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": [ { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" + "type": "string", + "description": "ID of the operation to use for the request." }, { "title": "Operation ID", @@ -1894,7 +11971,166 @@ { "allOf": [ { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0" + "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", @@ -2281,7 +12517,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -2290,7 +12581,240 @@ ], "properties": { "runShell": { - "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0" + "$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" @@ -2300,7 +12824,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -2314,7 +12893,92 @@ "description": "Assemble and run code.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/6/allOf/1/properties/runCode/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)" } ], "components": { @@ -2443,17 +13107,72 @@ "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": "runCode" - } - ] - }, - { - "allOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + "title": "Common" }, { "type": "object", @@ -2467,10 +13186,108 @@ "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": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/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 } ], "components": { @@ -2499,7 +13316,23 @@ "type": "object", "properties": { "keys": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] }, "inputDelay": { "type": "number", @@ -2599,7 +13432,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -2613,10 +13501,192 @@ "description": "Takes a screenshot in PNG format.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/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." + } + ] + } + } + } + ] + } + }, + "title": "Capture screenshot (detailed)" }, { "type": "boolean", @@ -2640,7 +13710,13 @@ "additionalProperties": false, "properties": { "path": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/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" + ] }, "directory": { "type": "string", @@ -2674,7 +13750,134 @@ "description": "Display text or selector of the element to screenshot." }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/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." + } + ] + } + } } ] } @@ -2784,7 +13987,28 @@ "minimum": 0 }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/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." } ] } @@ -2860,7 +14084,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -2874,10 +14153,107 @@ "description": "Save a specific browser cookie to a file or environment variable for later reuse.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/components/schemas/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)" } ], "components": { @@ -3024,7 +14400,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -3038,10 +14469,42 @@ "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": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/components/schemas/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)" }, { "type": "boolean", @@ -3109,7 +14572,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -3139,7 +14657,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "loadVariables", @@ -3149,7 +14722,13 @@ ], "properties": { "loadVariables": { - "$ref": "#/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" + ] } } } @@ -3158,7 +14737,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "dragAndDrop", @@ -3178,12 +14812,222 @@ ], "properties": { "source": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", - "description": "The element to drag." + "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", - "description": "The target location to drop the element." + "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", @@ -3197,10 +15041,108 @@ "elementSpecification": { "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/string" + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/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 + } + } } ] }, @@ -3362,7 +15304,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "loadCookie", @@ -3377,10 +15374,101 @@ "description": "Load a specific cookie from a file or environment variable into the browser.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/components/schemas/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)" } ], "components": { @@ -3515,7 +15603,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "wait", @@ -3535,7 +15678,12 @@ "title": "Wait (simple)" }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/15/allOf/1/properties/wait/components/schemas/string" + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] }, { "type": "boolean", @@ -3713,108 +15861,223 @@ } }, { - "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/0" - } + "find": "Find me!" }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/1" + "selector": "[title=Search]" } }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/2" + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" } }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/3" + "selector": "[title=Search]", + "click": { + "button": "right" + } } }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/4" + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } } }, { - "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/0" - } + "click": true }, { - "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/1" - } + "click": "right" }, { "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/2" + "button": "left", + "elementText": "Element text" } }, { "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/3" + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" } }, { - "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/0" - } + "httpRequest": "https://reqres.in/api/users" }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/1" + "url": "https://reqres.in/api/users" } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/2" + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/3" + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/4" + "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/5" + "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/6" + "openApi": "getUserById" } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/7" + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/8" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/9" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/10" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/11" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } } }, { @@ -3900,7 +16163,10 @@ "description": "Nested matchers for child nodes. All child matchers must match at least one child.", "type": "array", "items": { - "$ref": "#/components/schemas/astNodeMatch" + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": {}, + "title": "AST node match configuration" } }, "extract": { @@ -3950,7 +16216,18 @@ "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": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -3958,7 +16235,18 @@ "description": "Regular expressions that indicate that the current test is complete.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -3966,7 +16254,18 @@ "description": "Regular expressions that indicates that the following content should be ignored for testing purposes.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -3974,7 +16273,18 @@ "description": "Regular expressions that indicate that the ignored section of content is complete.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -3982,7 +16292,18 @@ "description": "Regular expressions that indicate a step in a test.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] } diff --git a/common/dist/schemas/resolvedTests_v3.schema.json b/common/dist/schemas/resolvedTests_v3.schema.json index 0de7347..79ba272 100644 --- a/common/dist/schemas/resolvedTests_v3.schema.json +++ b/common/dist/schemas/resolvedTests_v3.schema.json @@ -196,7 +196,12 @@ { "type": "array", "items": { - "type": "string" + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] } } ] @@ -226,6 +231,12 @@ "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": { @@ -275,12 +286,71 @@ { "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" } ] @@ -292,17 +362,81 @@ "components": { "schemas": { "platform": { - "type": "string" + "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" } } @@ -462,7 +596,20 @@ "extensions": { "description": "File extensions to use with type.", "anyOf": [ - {} + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } ] }, "inlineStatements": { @@ -472,31 +619,96 @@ "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" + } + } + ] + } ] } }, @@ -580,7 +792,13 @@ "items": { "type": "object", "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", - "properties": {}, + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} + }, "title": "AST node match configuration" } }, @@ -606,7 +824,20 @@ "regex": { "description": "Regular expressions to match the markup type.", "anyOf": [ - {} + { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } ] }, "batchMatches": { @@ -642,7 +873,24 @@ "items": { "anyOf": [ { - "type": "string" + "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#", @@ -711,7 +959,10 @@ }, "$schema": { "description": "JSON Schema for this object.", - "type": "string" + "type": "string", + "enum": [ + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/step_v3.schema.json" + ] }, "stepId": { "type": "string", @@ -729,11 +980,25 @@ "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": { @@ -748,6 +1013,60 @@ "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" }, { @@ -827,13 +1146,61 @@ "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_]+$)" + "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 + "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 + ] + } + } } } }, @@ -862,6 +1229,60 @@ "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" }, { @@ -996,11 +1417,115 @@ }, "button": { "description": "Kind of click to perform.", - "type": "string" + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] }, "object": { "title": "Click element (detailed)", - "type": "object" + "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." + } + } } } }, @@ -1027,20 +1552,74 @@ "allOf": [ { "type": "object", - "title": "Common" - }, - { - "type": "object", - "required": [ - "find" - ], + "dynamicDefaults": { + "stepId": "uuid" + }, "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": [ - { + "$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." @@ -1154,14 +1733,266 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "click", - "description": "Click or tap an element." + "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" + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] } }, "title": "Find element and click" @@ -1201,7 +2032,22 @@ "properties": { "keys": { "title": "Type keys (simple)", - "description": "Sequence of keys to enter." + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] }, "inputDelay": { "type": "number", @@ -1270,11 +2116,106 @@ "schemas": { "keys": { "title": "Type keys (simple)", - "description": "Sequence of keys to enter." + "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 } } @@ -1335,338 +2276,695 @@ "object": { "title": "Find element (detailed)", "type": "object", - "additionalProperties": false - } - } - }, - "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" + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } ], - "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", - "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" + "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" } - ], - "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, + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { "anyOf": [ { - "required": [ - "selector" - ] - }, - { - "required": [ - "elementText" - ] - }, - { - "required": [ - "elementId" - ] - }, - { - "required": [ - "elementTestId" - ] - }, - { - "required": [ - "elementClass" - ] + "type": "string" }, { - "required": [ - "elementAttribute" - ] + "type": "number" }, { - "required": [ - "elementAria" - ] + "type": "boolean" } - ], - "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": { + ] + } + }, + "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": [ { - "type": "string" + "required": [ + "selector" + ] }, { - "type": "number" + "required": [ + "elementText" + ] }, { - "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_]+)" - }, - "object": { - "description": "Navigate to an HTTP or HTTPS URL.", - "type": "object", - "additionalProperties": false, - "title": "Go to URL (detailed)" + "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": [ - "https://www.google.com", - "/search", + "Find me!", { - "url": "https://www.google.com" + "selector": "[title=Search]" }, { - "url": "/search", - "origin": "https://www.google.com" + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" }, { - "url": "https://www.example.com", - "waitUntil": { - "networkIdleTime": 500 + "selector": "[title=Search]", + "click": { + "button": "right" } }, { - "url": "https://www.example.com/dashboard", - "waitUntil": { - "find": { - "selector": "[data-testid='dashboard-loaded']" - } + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 } }, { - "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" - } - } - } + "elementId": "/^user-[0-9]+$/", + "elementClass": [ + "admin", + "/^level-[1-5]$/" + ], + "elementAttribute": { + "data-active": true, + "data-score": "/^[0-9]+$/" + }, + "timeout": 8000, + "moveTo": false } ] } }, - "title": "goTo" + "title": "find" } ] }, @@ -1674,614 +2972,481 @@ "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" + "goTo" ], "properties": { - "httpRequest": { + "goTo": { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "httpRequest", - "description": "Perform a generic HTTP request, for example to an API.", + "title": "goTo", "anyOf": [ { - "title": "HTTP request (simple)", + "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", - "description": "URL for the HTTP request.", - "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", "transform": [ "trim" ] }, { - "title": "HTTP request (detailed)", + "description": "Navigate to an HTTP or HTTPS URL.", "type": "object", - "anyOf": [ - { - "required": [ - "url" - ] - }, - { - "required": [ - "openApi" - ] - } - ], "additionalProperties": false, + "required": [ + "url" + ], "properties": { "url": { - "title": "HTTP request (simple)", "type": "string", - "description": "URL for the HTTP request.", - "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)" + "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" + ] }, - "openApi": { - "anyOf": [ - { - "allOf": [ + "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": "string", - "description": "ID of the operation to use for the request." + "type": "integer", + "minimum": 0 }, { - "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." + "type": "null" } - ] + ], + "default": 500 }, - { - "allOf": [ + "domIdleTime": { + "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "anyOf": [ { - "version": "1.0.0", - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "openApi", - "type": "object", - "description": "OpenAPI description and configuration.", - "additionalProperties": false, + "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": [ { - "required": [ - "descriptionPath" - ] + "type": "string" }, { - "required": [ - "operationId" - ] + "type": "array", + "items": { + "type": "string" + } } ], - "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": { + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { "type": "string" }, - "title": "OpenAPI request headers" - } - }, - "components": { - "schemas": { - "operationId": { - "type": "string", - "description": "ID of the operation to use for the request." + { + "type": "number" }, - "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": "boolean" } - } - ] + ] + } }, - { - "type": "object", - "required": [ - "operationId" - ], - "title": "OpenAPI definition (httpRequest)" + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." } - ] - } - ] - }, - "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" } + } + } + } + }, + "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" ] }, - "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": {} - } + "origin": { + "type": "string", + "description": "Protocol and domain to navigate to. Prepended to `url`.", + "transform": [ + "trim" + ] }, - "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" + "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 }, - "default": [] + "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": "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_]+)" - }, - "object": { - "title": "HTTP request (detailed)", - "type": "object", - "additionalProperties": false + "title": "Go to URL (detailed)" } } }, "examples": [ - "https://reqres.in/api/users", + "https://www.google.com", + "/search", { - "url": "https://reqres.in/api/users" + "url": "https://www.google.com" }, { - "url": "https://reqres.in/api/users/2", - "method": "put", - "request": { - "body": { - "name": "morpheus", - "job": "zion resident" - } - } + "url": "/search", + "origin": "https://www.google.com" }, { - "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.example.com", + "waitUntil": { + "networkIdleTime": 500 + } }, { - "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" + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" } - }, - "statusCodes": [ - 200 - ] + } }, { - "url": "https://reqres.in/api/users", - "method": "post", - "request": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "response": { - "body": { - "name": "morpheus", - "job": "leader" + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" } - }, - "statusCodes": [ - 200, - 201 - ], - "path": "response.json", - "directory": "media", - "maxVariation": 0.05, - "overwrite": "aboveVariation" + } }, { - "openApi": "getUserById" + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } }, { - "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.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" } } }, { - "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" + "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" } } } @@ -2289,7 +3454,7 @@ ] } }, - "title": "httpRequest" + "title": "goTo" } ] }, @@ -2297,1848 +3462,12881 @@ "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" + "httpRequest" ], "properties": { - "runShell": { + "httpRequest": { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "runShell", - "description": "Perform a native shell command.", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", "anyOf": [ { - "title": "Run shell command (simple)", - "description": "Command to perform in the machine's default shell.", + "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", - "required": [ - "command" + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } ], "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": { + "url": { + "title": "HTTP request (simple)", "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 + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" ] }, - "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" - }, - "object": { - "type": "object", - "additionalProperties": false, - "title": "Run shell command (detailed)" - } - } - }, - "examples": [ - "docker run hello-world", - { - "command": "echo", - "args": [ - "$USER" - ] + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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" + } + }, + "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", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} + }, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "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 }, { - "command": "echo", - "args": [ - "hello-world" + "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" ] }, { - "command": "docker run hello-world", - "timeout": 20000, - "exitCodes": [ - 0 - ], - "stdio": "Hello from Docker!" + "required": [ + "elementText" + ] }, { - "command": "false", - "exitCodes": [ - 1 + "required": [ + "elementId" ] }, { - "command": "echo", - "args": [ - "setup" - ], - "exitCodes": [ - 0 - ], - "stdio": "/.*?/" + "required": [ + "elementTestId" + ] }, { - "command": "docker run hello-world", - "workingDirectory": ".", - "exitCodes": [ - 0 + "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" + } + } ], - "stdio": "Hello from Docker!", - "path": "docker-output.txt", - "directory": "output", - "maxVariation": 0.1, - "overwrite": "aboveVariation" + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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": "runShell" + } } - ] - }, - { - "allOf": [ - { - "type": "object", - "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.", + }, + "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" }, - "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": { + "title": "OpenAPI request headers" + } + }, + "components": { + "schemas": { + "operationId": { "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 + "description": "ID of the operation to use for the request." }, - "overwrite": { + "descriptionPath": { "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 + "description": "URL or local path to the OpenAPI description." } + } + }, + "examples": [ + { + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" }, - "title": "Run code (detailed)" - } - ], - "components": { - "schemas": { - "object": { - "type": "object", - "title": "Run code (detailed)" + { + "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" + } } - } + ] }, - "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" - } - ] + { + "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" + } + ] }, - "title": "runCode" - } - ] - }, - { - "allOf": [ - { - "type": "object", - "title": "Common" + "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": {} + } }, - { - "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$`." - } + "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" }, - "title": "type" - } + "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" ] }, - { - "allOf": [ + "object": { + "title": "HTTP request (detailed)", + "type": "object", + "anyOf": [ { - "type": "object", - "title": "Common" + "required": [ + "url" + ] }, { - "type": "object", - "required": [ - "screenshot" - ], - "properties": { - "screenshot": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "screenshot", - "description": "Takes a screenshot in PNG format.", - "anyOf": [ + "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": [ { - "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" - ] + "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": { - "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.", + "name": { "type": "string", - "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)" + "description": "Name of the OpenAPI description, as defined in your configuration." }, - "directory": { + "descriptionPath": { "type": "string", - "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory.", - "transform": [ - "trim" - ] + "description": "URL or local path to the OpenAPI description." }, - "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 + "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" }, - "overwrite": { + "operationId": { "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`.", + "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": [ - "true", - "false", - "aboveVariation" + "request", + "response", + "both", + "none" ], - "default": "aboveVariation" + "default": "both" }, - "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." - } - ] - } - } - } - ] + "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" } }, - "title": "Capture screenshot (detailed)" + "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": {} }, { - "type": "boolean", - "title": "Capture screenshot", - "description": "If `true`, captures a screenshot. If `false`, doesn't capture a screenshot." + "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" } ], - "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_]+)" - }, - "object": { - "type": "object", - "additionalProperties": false, - "title": "Capture screenshot (detailed)" - }, - "crop_element": { - "title": "Crop by element (detailed)", - "type": "object", - "description": "Crop the screenshot to a specific element.", - "additionalProperties": false - }, - "padding": { - "type": "object", - "additionalProperties": false, - "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", + "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": [ { - "path": "image.png", - "directory": "static/images", - "maxVariation": 0.1, - "overwrite": "aboveVariation", - "crop": "#elementToScreenshot" + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." }, { - "path": "image.png", - "directory": "static/images", - "maxVariation": 0.1, - "overwrite": "aboveVariation" + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} }, { - "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": "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" }, - "title": "screenshot" + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] } - ] + }, + "elementAria": { + "type": "string", + "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + } }, - { - "allOf": [ + "required": [ + "keys" + ], + "additionalProperties": false + } + ], + "components": { + "schemas": { + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ { - "type": "object", - "title": "Common" + "type": "string" }, { - "type": "object", - "required": [ - "saveCookie" + "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" + } + } ], - "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" - ] - } + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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" }, - "required": [ - "name" - ], + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { "anyOf": [ { - "required": [ - "path" - ], - "not": { - "required": [ - "variable" - ] - } + "type": "string" }, { - "required": [ - "variable" - ], - "not": { - "anyOf": [ - { - "required": [ - "path" - ] - }, - { - "required": [ - "directory" - ] - } - ] - } + "type": "number" + }, + { + "type": "boolean" } - ], - "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_./\\-]+$" + }, + "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 }, - "object": { + { "type": "object", "additionalProperties": false, - "title": "Save cookie (detailed)" + "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": [ - "session_token", - "test_env_cookie", + ] + } + } + } + ] + } + }, + "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": [ { - "name": "auth_cookie", - "path": "auth-cookie.txt" + "required": [ + "selector" + ] }, { - "name": "session_token", - "variable": "SESSION_TOKEN" + "required": [ + "elementText" + ] }, { - "name": "test_cookie", - "path": "test-cookie.txt", - "overwrite": true + "required": [ + "elementId" + ] }, { - "name": "user_session", - "path": "user-session.txt", - "directory": "./test-data", - "overwrite": true + "required": [ + "elementTestId" + ] }, { - "name": "login_token", - "path": "login-token.txt", - "domain": "app.example.com" + "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." + } + ] + } + } + } + ] + } + }, + "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": "saveCookie" + ] } + } + ], + "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" ] }, - { - "allOf": [ + "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": [ { - "type": "object", - "title": "Common" + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } }, { - "type": "object", "required": [ - "record" + "variable" ], - "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_]+)" - }, - "object": { - "type": "object", - "title": "Record (detailed)" - } - } + "not": { + "anyOf": [ + { + "required": [ + "path" + ] }, - "examples": [ - true, - "results.mp4", - { - "path": "results.mp4", - "directory": "static/media", - "overwrite": "true" - } - ] - } + { + "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" + ] }, - "title": "record" - } - ] - }, - { - "allOf": [ - { - "type": "object", - "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 - ] - } + { + "required": [ + "elementText" + ] }, - "title": "stopRecord" - } - ] - }, - { - "allOf": [ - { - "type": "object", - "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." - } + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] } - } - ] - }, - { - "allOf": [ - { - "type": "object", - "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": [] - }, - "duration": { - "type": "integer", - "description": "Duration of the drag operation in milliseconds.", - "default": 1000, - "minimum": 0 - } - }, - "components": { - "schemas": { - "elementSpecification": { - "anyOf": [] - }, - "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" - } - } + ], + "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" }, - "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 - }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ { - "source": { - "selector": ".draggable", - "timeout": 10000 - }, - "target": { - "elementText": "Drop Zone", - "timeout": 5000 - } + "type": "string" }, { - "source": "/Widget Item.*/", - "target": "#canvas" + "type": "number" }, { - "source": { - "selector": ".draggable", - "elementText": "/Button [0-9]+/" - }, - "target": { - "elementText": "/Drop Zone.*/" - } + "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 } } - ] - }, - { - "allOf": [ - { - "type": "object", - "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_./\\-]+$" - }, - "object": { - "type": "object", - "additionalProperties": false, - "title": "Load cookie (detailed)" - } - } + } + ] + }, + "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" }, - "examples": [ - "session_token", - "./test-data/auth-session.txt", - "test_env_cookie", - { - "name": "auth_cookie", - "variable": "AUTH_COOKIE" - }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ { - "name": "test_cookie", - "path": "test-cookie.txt" + "type": "string" }, { - "name": "session_token", - "path": "session-token.txt", - "directory": "./test-data" + "type": "number" }, { - "name": "user_session", - "path": "saved-cookies.txt", - "domain": "app.example.com" + "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 } } - ] - }, - { - "allOf": [ + } + ] + }, + "duration": { + "type": "integer", + "description": "Duration of the drag operation in milliseconds.", + "default": 1000, + "minimum": 0 + } + }, + "components": { + "schemas": { + "elementSpecification": { + "anyOf": [ { - "type": "object", - "title": "Common" + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." }, { - "title": "wait", + "title": "Element (detailed)", "type": "object", - "required": [ - "wait" + "anyOf": [ + { + "required": [ + "selector" + ] + }, + { + "required": [ + "elementText" + ] + }, + { + "required": [ + "elementId" + ] + }, + { + "required": [ + "elementTestId" + ] + }, + { + "required": [ + "elementClass" + ] + }, + { + "required": [ + "elementAttribute" + ] + }, + { + "required": [ + "elementAria" + ] + } ], "properties": { - "wait": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "wait", - "description": "Pause (in milliseconds) before performing the next action.", - "default": 5000, + "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": "number", - "title": "Wait (simple)" - }, - { - "title": "Wait (environment variable)", - "type": "string", - "pattern": "(\\$[A-Za-z0-9_]+)", - "transform": [ - "trim" - ] + "type": "string" }, { - "type": "boolean", - "title": "Wait (boolean)" - } - ], - "components": { - "schemas": { - "string": { - "title": "Wait (environment variable)", - "type": "string", - "pattern": "(\\$[A-Za-z0-9_]+)" + "type": "array", + "items": { + "type": "string" } } - }, - "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]" - } - }, - { - "find": { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true - } - }, - { - "click": true - }, - { - "click": "right" - }, - { - "click": { - "button": "left", - "elementText": "Element text" - } - }, - { - "click": { - "selector": "#elementToScreenshot", - "elementText": "Element text", - "button": "middle" - } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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 + } + } + } + ] }, - { - "httpRequest": "https://reqres.in/api/users" + "string": { + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." }, - { - "httpRequest": { - "url": "https://reqres.in/api/users" + "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" }, - { - "httpRequest": { - "url": "https://reqres.in/api/users/2", - "method": "put" - } + "target": { + "selector": "#design-canvas" }, - { - "httpRequest": { - "url": "https://reqres.in/api/users", - "method": "post" - } + "duration": 500 + }, + { + "source": { + "selector": ".draggable", + "timeout": 10000 }, - { - "httpRequest": { - "url": "https://www.api-server.com", - "method": "post", - "timeout": 30000 - } + "target": { + "elementText": "Drop Zone", + "timeout": 5000 + } + }, + { + "source": "/Widget Item.*/", + "target": "#canvas" + }, + { + "source": { + "selector": ".draggable", + "elementText": "/Button [0-9]+/" }, - { - "httpRequest": { - "url": "https://reqres.in/api/users", - "method": "post", - "path": "response.json", - "directory": "media", - "maxVariation": 0.05, - "overwrite": "aboveVariation" + "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" + ] + } + ] + } } - }, - { - "httpRequest": { - "openApi": "getUserById" + ], + "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" + ] } }, - { - "httpRequest": {} - }, - { - "httpRequest": {} - }, - { - "httpRequest": {} - }, - { - "httpRequest": {} - }, - { - "httpRequest": {} - }, - { - "stepId": "breakpoint-example", - "description": "Step with breakpoint enabled", - "goTo": "https://www.example.com", - "breakpoint": true - }, - { - "checkLink": "https://www.google.com", - "breakpoint": false + "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" + ] }, - { - "dragAndDrop": { - "source": { - "selector": "#sourceElement" + "object": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "anyOf": [ + { + "required": [ + "path" + ], + "not": { + "required": [ + "variable" + ] + } }, - "target": { - "selector": "#targetElement" + { + "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 } } - ] - } - }, - "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": [ - {} - ] - }, - "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." - } - ] - } + } + }, + { + "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" + } + } + } + ] + } + ] } } ] } - } - ] - }, - "integrations": { - "description": "Options for connecting to external services.", - "type": "object", - "additionalProperties": false, - "properties": { - "openApi": { - "type": "array", - "items": { - "allOf": [ + }, + "title": "Markup definition" + }, + "astNodeMatch": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ { - "version": "1.0.0", - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "openApi", - "type": "object", - "description": "OpenAPI description and configuration.", - "additionalProperties": false + "type": "string" }, { - "type": "object", - "not": { - "required": [ - "operationId" - ] + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" }, - "required": [ - "name", - "descriptionPath" - ], - "title": "OpenAPI description (test)" + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" } ] - } - }, - "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." + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": {}, + "title": "AST node match configuration" } }, - "title": "Doc Detective Orchestration API" - } - }, - "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" + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } }, - { - "type": "string", - "enum": [ - "stepThrough" - ] - } - ], - "default": false - } - }, - "components": { - "schemas": { - "environment": { - "type": "object", - "description": "Environment information for the system running Doc Detective.", - "readOnly": true, - "additionalProperties": false, - "title": "Environment details" - }, - "markupDefinition": { - "type": "object", - "title": "Markup definition" - }, - "astNodeMatch": { - "type": "object", - "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", "title": "AST node match configuration" }, "markupActionString": { - "type": "string" + "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": {} + "stringOrArray": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } } }, "examples": [ @@ -4359,10 +16557,567 @@ }, "runOn": { "type": "array", - "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels." + "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" + "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.", @@ -4395,10 +17150,567 @@ }, "runOn": { "type": "array", - "description": "Contexts to run the test in. Overrides contexts defined at the config and spec levels." + "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" + "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", @@ -4416,7 +17728,7220 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "step", "description": "A step in a test.", - "type": "object" + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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": { @@ -4434,11 +24959,243 @@ "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" + "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.", @@ -4448,7 +25205,7220 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "step", "description": "A step in a test.", - "type": "object" + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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" + } + } + } + ] } } }, @@ -4475,7 +32445,186 @@ "components": { "schemas": { "openApi": { - "type": "array" + "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)" + } + ] + } } } }, diff --git a/common/src/schemas/dereferenceSchemas.js b/common/src/schemas/dereferenceSchemas.js index 5b806f2..6e113ac 100644 --- a/common/src/schemas/dereferenceSchemas.js +++ b/common/src/schemas/dereferenceSchemas.js @@ -112,23 +112,54 @@ async function dereferenceSchemas() { let schema = fs.readFileSync(filePath).toString(); schema = JSON.parse(schema); - // Check if this is config_v3 which has recursive schemas (astNodeMatch) - // For recursive schemas, use bundle instead of dereference to preserve $refs - const hasRecursiveSchemas = file.includes('config_v3'); + // Check if this schema has recursive references + // config_v3 has astNodeMatch.children which is recursive + // resolvedTests_v3 references config_v3, so also needs special handling + const schemasWithRecursion = ['config_v3', 'resolvedTests_v3']; + const hasRecursiveSchemas = schemasWithRecursion.some(s => file.includes(s)); + + // Always dereference fully - but handle circular refs in the output + schema = await parser.dereference(schema); + // Delete $id attributes + schema = deleteDollarIds(schema); if (hasRecursiveSchemas) { - // Bundle keeps $refs for recursive schemas while resolving others - schema = await parser.bundle(schema); + // Deep clone that breaks circular references by tracking visited objects + // When a circular ref is encountered, it creates a fresh copy with primitive values only + const breakCircularRefs = (obj, ancestors = new Set()) => { + if (obj === null || typeof obj !== 'object') return obj; + + // If we've seen this object in the current path, it's circular + if (ancestors.has(obj)) { + // Create a shallow copy with only non-object properties + // This breaks the cycle while preserving structure + const shallowCopy = Array.isArray(obj) ? [] : {}; + for (const [k, v] of Object.entries(obj)) { + if (v === null || typeof v !== 'object') { + shallowCopy[k] = v; + } else if (Array.isArray(v)) { + shallowCopy[k] = []; + } else { + shallowCopy[k] = {}; + } + } + return shallowCopy; + } + + ancestors.add(obj); + const result = Array.isArray(obj) ? [] : {}; + for (const [k, v] of Object.entries(obj)) { + result[k] = breakCircularRefs(v, ancestors); + } + ancestors.delete(obj); + return result; + }; + + const cleanSchema = breakCircularRefs(schema); + fs.writeFileSync(outputFilePath, JSON.stringify(cleanSchema, null, 2)); } else { - // Dereference fully resolves all $refs - schema = await parser.dereference(schema); + fs.writeFileSync(outputFilePath, JSON.stringify(schema, null, 2)); } - - // Delete $id attributes - schema = deleteDollarIds(schema); - - // Write to file - fs.writeFileSync(outputFilePath, JSON.stringify(schema, null, 2)); } catch (err) { console.error(`Error processing ${file}:`, err); } diff --git a/common/src/schemas/output_schemas/config_v3.schema.json b/common/src/schemas/output_schemas/config_v3.schema.json index d408b02..c1d8b30 100644 --- a/common/src/schemas/output_schemas/config_v3.schema.json +++ b/common/src/schemas/output_schemas/config_v3.schema.json @@ -29,7 +29,18 @@ "default": ".", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -162,12 +173,22 @@ "description": "Platforms to run tests on.", "anyOf": [ { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] }, { "type": "array", "items": { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] } } ] @@ -176,20 +197,148 @@ "description": "Browsers to run tests on.", "anyOf": [ { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." }, { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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" }, { "type": "array", "items": { "anyOf": [ { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." }, { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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" } ] } @@ -227,7 +376,15 @@ "additionalProperties": false, "properties": { "name": { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." }, "headless": { "type": "boolean", @@ -427,144 +584,7744 @@ "description": "File extensions to use with type.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, "inlineStatements": { - "$ref": "#/components/schemas/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": { - "$ref": "#/components/schemas/markupDefinition" - } - } - } - }, - { - "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": [ - { - "$ref": "#/components/schemas/stringOrArray" - } - ] - }, - "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": [ - { - "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/string" - }, - { - "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/object" - } - ], - "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." + "type": "object", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" }, - "args": { + { "type": "array", - "description": "Arguments for the command.", "items": { - "anyOf": [ - { - "type": "string" - } - ] + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "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" - } - ] + { + "type": "boolean" }, - "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`." + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" }, - "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." + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} }, - "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 + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" }, - "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" + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" }, - "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 + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } } - }, - "title": "Run shell command (detailed)" + ] } - } + ] + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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", @@ -661,7 +8418,8 @@ "description": "Name of the OpenAPI description, as defined in your configuration." }, "descriptionPath": { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/descriptionPath" + "type": "string", + "description": "URL or local path to the OpenAPI description." }, "definition": { "type": "object", @@ -671,7 +8429,8 @@ "title": "OpenAPI definition" }, "operationId": { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" + "type": "string", + "description": "ID of the operation to use for the request." }, "server": { "type": "string", @@ -863,7 +8622,39 @@ } }, "environment": { - "$ref": "#/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" }, "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.", @@ -939,13 +8730,104 @@ }, "ast": { "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", - "$ref": "#/components/schemas/astNodeMatch" + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} + }, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" }, "regex": { "description": "Regular expressions to match the markup type.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -958,14 +8840,48 @@ "description": "Actions to perform when the markup type is detected.", "anyOf": [ { - "$ref": "#/components/schemas/markupActionString" + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] }, { "type": "array", "items": { "anyOf": [ { - "$ref": "#/components/schemas/markupActionString" + "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#", @@ -981,25 +8897,53 @@ }, "properties": { "$schema": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/$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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/stepId" + "type": "string", + "description": "ID of the step." }, "description": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/description" + "type": "string", + "description": "Description of the step." }, "unsafe": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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" @@ -1059,7 +9003,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -1072,10 +9071,64 @@ "title": "checkLink", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/components/schemas/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 + ] + } + } } ], "components": { @@ -1166,7 +9219,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -1180,10 +9288,112 @@ "description": "Click or tap an element.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/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." }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/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." + } + } }, { "type": "boolean" @@ -1247,7 +9457,13 @@ ], "properties": { "button": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] }, "elementText": { "type": "string", @@ -1275,76 +9491,771 @@ "items": { "type": "string" } - } - ], - "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." - }, - "elementAttribute": { - "type": "object", - "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", - "additionalProperties": { - "anyOf": [ + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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$" + ], { - "type": "string" + "keys": "kittens" }, { - "type": "number" + "keys": [ + "$ENTER$" + ] }, { - "type": "boolean" + "keys": [ + "kittens", + "$ENTER$" + ], + "inputDelay": 500 } ] + }, + { + "not": { + "type": "object", + "required": [ + "selector", + "elementText", + "elementId", + "elementTestId", + "elementClass", + "elementAttribute", + "elementAria" + ], + "title": "Find element and type" + } } - }, - "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": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/string" - }, - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/object" - } ], "components": { "schemas": { @@ -1460,13 +10371,268 @@ "description": "Click the element.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/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" + } + ] }, { "type": "object", "properties": { "button": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" + "description": "Kind of click to perform.", + "type": "string", + "enum": [ + "left", + "right", + "middle" + ] } }, "title": "Find element and click" @@ -1477,7 +10643,248 @@ "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": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/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 + } + ] }, { "not": { @@ -1545,17 +10952,72 @@ "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": "find" - } - ] - }, - { - "allOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + "title": "Common" }, { "type": "object", @@ -1568,10 +11030,173 @@ "title": "goTo", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/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)" } ], "components": { @@ -1827,7 +11452,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -1841,10 +11521,400 @@ "description": "Perform a generic HTTP request, for example to an API.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/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" + } + } } ], "components": { @@ -1876,14 +11946,21 @@ "additionalProperties": false, "properties": { "url": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/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": [ { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" + "type": "string", + "description": "ID of the operation to use for the request." }, { "title": "Operation ID", @@ -1894,7 +11971,166 @@ { "allOf": [ { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0" + "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", @@ -2281,7 +12517,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -2290,7 +12581,240 @@ ], "properties": { "runShell": { - "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0" + "$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" @@ -2300,7 +12824,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -2314,7 +12893,92 @@ "description": "Assemble and run code.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/6/allOf/1/properties/runCode/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)" } ], "components": { @@ -2443,17 +13107,72 @@ "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": "runCode" - } - ] - }, - { - "allOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + "title": "Common" }, { "type": "object", @@ -2467,10 +13186,108 @@ "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": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/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 } ], "components": { @@ -2499,7 +13316,23 @@ "type": "object", "properties": { "keys": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] }, "inputDelay": { "type": "number", @@ -2599,7 +13432,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -2613,10 +13501,192 @@ "description": "Takes a screenshot in PNG format.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/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." + } + ] + } + } + } + ] + } + }, + "title": "Capture screenshot (detailed)" }, { "type": "boolean", @@ -2640,7 +13710,13 @@ "additionalProperties": false, "properties": { "path": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/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" + ] }, "directory": { "type": "string", @@ -2674,7 +13750,134 @@ "description": "Display text or selector of the element to screenshot." }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/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." + } + ] + } + } } ] } @@ -2784,7 +13987,28 @@ "minimum": 0 }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/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." } ] } @@ -2860,7 +14084,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -2874,10 +14153,107 @@ "description": "Save a specific browser cookie to a file or environment variable for later reuse.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/components/schemas/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)" } ], "components": { @@ -3024,7 +14400,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -3038,10 +14469,42 @@ "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": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/components/schemas/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)" }, { "type": "boolean", @@ -3109,7 +14572,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -3139,7 +14657,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "loadVariables", @@ -3149,7 +14722,13 @@ ], "properties": { "loadVariables": { - "$ref": "#/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" + ] } } } @@ -3158,7 +14737,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "dragAndDrop", @@ -3178,12 +14812,222 @@ ], "properties": { "source": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", - "description": "The element to drag." + "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", - "description": "The target location to drop the element." + "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", @@ -3197,10 +15041,108 @@ "elementSpecification": { "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/string" + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/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 + } + } } ] }, @@ -3362,7 +15304,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "loadCookie", @@ -3377,10 +15374,101 @@ "description": "Load a specific cookie from a file or environment variable into the browser.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/components/schemas/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)" } ], "components": { @@ -3515,7 +15603,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "wait", @@ -3535,7 +15678,12 @@ "title": "Wait (simple)" }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/15/allOf/1/properties/wait/components/schemas/string" + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] }, { "type": "boolean", @@ -3713,108 +15861,223 @@ } }, { - "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/0" - } + "find": "Find me!" }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/1" + "selector": "[title=Search]" } }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/2" + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" } }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/3" + "selector": "[title=Search]", + "click": { + "button": "right" + } } }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/4" + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } } }, { - "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/0" - } + "click": true }, { - "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/1" - } + "click": "right" }, { "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/2" + "button": "left", + "elementText": "Element text" } }, { "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/3" + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" } }, { - "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/0" - } + "httpRequest": "https://reqres.in/api/users" }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/1" + "url": "https://reqres.in/api/users" } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/2" + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/3" + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/4" + "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/5" + "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/6" + "openApi": "getUserById" } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/7" + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/8" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/9" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/10" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/11" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } } }, { @@ -3900,7 +16163,10 @@ "description": "Nested matchers for child nodes. All child matchers must match at least one child.", "type": "array", "items": { - "$ref": "#/components/schemas/astNodeMatch" + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": {}, + "title": "AST node match configuration" } }, "extract": { @@ -3950,7 +16216,18 @@ "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": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -3958,7 +16235,18 @@ "description": "Regular expressions that indicate that the current test is complete.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -3966,7 +16254,18 @@ "description": "Regular expressions that indicates that the following content should be ignored for testing purposes.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -3974,7 +16273,18 @@ "description": "Regular expressions that indicate that the ignored section of content is complete.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -3982,7 +16292,18 @@ "description": "Regular expressions that indicate a step in a test.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] } diff --git a/common/src/schemas/output_schemas/resolvedTests_v3.schema.json b/common/src/schemas/output_schemas/resolvedTests_v3.schema.json new file mode 100644 index 0000000..79ba272 --- /dev/null +++ b/common/src/schemas/output_schemas/resolvedTests_v3.schema.json @@ -0,0 +1,33172 @@ +{ + "$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", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} + }, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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" + } + }, + "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", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} + }, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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" + }, + "astNodeMatch": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": {}, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "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 + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": [ + "md" + ], + "markup": [ + { + "name": "bashCodeBlock", + "ast": { + "nodeType": "code", + "attributes": { + "lang": [ + "bash", + "sh" + ] + }, + "extract": { + "$1": "attributes.lang", + "$2": "value" + } + }, + "actions": [ + { + "runCode": { + "language": "$1", + "code": "$2" + } + } + ] + } + ] + } + ] + }, + { + "fileTypes": [ + { + "extends": "dita", + "extensions": [ + "dita", + "xml" + ], + "markup": [ + { + "name": "ditaCodeblock", + "ast": { + "nodeType": "element", + "attributes": { + "tagName": "codeblock", + "outputclass": [ + "bash", + "shell" + ] + }, + "extract": { + "$1": "attributes.outputclass", + "$2": "content" + } + }, + "actions": [ + { + "runShell": { + "command": "$2" + } + } + ] + } + ] + } + ] + } + ] + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/schemas/schemas.json b/common/src/schemas/schemas.json index 3c8b70d..5140fdb 100644 --- a/common/src/schemas/schemas.json +++ b/common/src/schemas/schemas.json @@ -427,7 +427,18 @@ "default": ".", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -560,12 +571,22 @@ "description": "Platforms to run tests on.", "anyOf": [ { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] }, { "type": "array", "items": { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/platform" + "type": "string", + "enum": [ + "linux", + "mac", + "windows" + ] } } ] @@ -574,20 +595,148 @@ "description": "Browsers to run tests on.", "anyOf": [ { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." }, { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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" }, { "type": "array", "items": { "anyOf": [ { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." }, { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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" } ] } @@ -625,7 +774,15 @@ "additionalProperties": false, "properties": { "name": { - "$ref": "#/properties/runOn/items/anyOf/0/components/schemas/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." }, "headless": { "type": "boolean", @@ -825,198 +982,7798 @@ "description": "File extensions to use with type.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, "inlineStatements": { - "$ref": "#/components/schemas/inlineStatements" - }, - "markup": { - "description": "Markup definitions for the file type.", - "type": "array", - "minItems": 1, - "items": { - "$ref": "#/components/schemas/markupDefinition" - } - } - } - }, - { - "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": [ - { - "$ref": "#/components/schemas/stringOrArray" - } - ] - }, - "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.", + "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": [ { - "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/string" - }, + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] + } + ] + }, + "testEnd": { + "description": "Regular expressions that indicate that the current test is complete.", + "anyOf": [ { - "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0/components/schemas/object" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } - ], - "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." + ] + }, + "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", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" }, - "args": { + { "type": "array", - "description": "Arguments for the command.", "items": { - "anyOf": [ - { - "type": "string" - } - ] + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "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" - } - ] + { + "type": "boolean" }, - "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`." + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" }, - "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." + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} }, - "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 + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" }, - "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" + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "regex": { + "description": "Regular expressions to match the markup type.", + "anyOf": [ + { + "anyOf": [ + { + "type": "string" }, - "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 + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } } - }, - "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" - } - ] - } - ] + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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" + } + ] + } + ] } } } @@ -1059,7 +8816,8 @@ "description": "Name of the OpenAPI description, as defined in your configuration." }, "descriptionPath": { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/descriptionPath" + "type": "string", + "description": "URL or local path to the OpenAPI description." }, "definition": { "type": "object", @@ -1069,7 +8827,8 @@ "title": "OpenAPI definition" }, "operationId": { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" + "type": "string", + "description": "ID of the operation to use for the request." }, "server": { "type": "string", @@ -1261,7 +9020,39 @@ } }, "environment": { - "$ref": "#/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" }, "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.", @@ -1337,13 +9128,104 @@ }, "ast": { "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", - "$ref": "#/components/schemas/astNodeMatch" + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} + }, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" }, "regex": { "description": "Regular expressions to match the markup type.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -1356,14 +9238,48 @@ "description": "Actions to perform when the markup type is detected.", "anyOf": [ { - "$ref": "#/components/schemas/markupActionString" + "type": "string", + "enum": [ + "checkLink", + "click", + "find", + "goTo", + "httpRequest", + "loadCookie", + "loadVariables", + "record", + "runCode", + "runShell", + "saveCookie", + "screenshot", + "stopRecord", + "type", + "wait" + ] }, { "type": "array", "items": { "anyOf": [ { - "$ref": "#/components/schemas/markupActionString" + "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#", @@ -1374,122 +9290,2326 @@ "schemas": { "common": { "type": "object", - "dynamicDefaults": { - "stepId": "uuid" + "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." + } }, - "properties": { - "$schema": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/$schema" + "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" }, - "stepId": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/stepId" + "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 + } }, - "description": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/description" + "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" + } + ] + } }, - "unsafe": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/unsafe" + "title": "click" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "dynamicDefaults": { + "stepId": "uuid" }, - "outputs": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/outputs" + "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 + } }, - "variables": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/variables" + "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 + } + ] + } }, - "breakpoint": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/breakpoint" - } - }, - "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": [ + "title": "find" + } + ] + }, { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", "required": [ - "checkLink" + "goTo" ], "properties": { - "checkLink": { + "goTo": { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "checkLink", + "title": "goTo", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/0/allOf/1/properties/checkLink/components/schemas/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)" } ], "components": { "schemas": { "string": { - "title": "Check link (detailed)", - "description": "Check if an HTTP or HTTPS URL returns an acceptable status code from a GET request.", + "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_]+$)", + "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.", + "description": "Navigate to an HTTP or HTTPS URL.", "type": "object", "additionalProperties": false, "required": [ @@ -1498,7 +11618,7 @@ "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.", + "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" @@ -1511,32 +11631,142 @@ "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" + "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 }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "integer" + "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." + } } } - ], - "default": [ - 200, - 301, - 302, - 307, - 308 - ] + } } - } + }, + "title": "Go to URL (detailed)" } } }, @@ -1544,673 +11774,1133 @@ "https://www.google.com", "/search", { - "url": "https://www.google.com", - "statusCodes": 200 + "url": "https://www.google.com" }, { "url": "/search", - "origin": "www.google.com", - "statusCodes": [ - 200 - ] - } - ] - } - }, - "title": "checkLink" - } - ] - }, - { - "allOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" - }, - { - "type": "object", - "required": [ - "click" - ], - "properties": { - "click": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "click", - "description": "Click or tap an element.", - "anyOf": [ + "origin": "https://www.google.com" + }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/string" + "url": "https://www.example.com", + "waitUntil": { + "networkIdleTime": 500 + } }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/object" + "url": "https://www.example.com/dashboard", + "waitUntil": { + "find": { + "selector": "[data-testid='dashboard-loaded']" + } + } }, { - "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" - }, - "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." - } + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": 500, + "domIdleTime": 1000, + "find": { + "selector": ".main-content", + "elementText": "Dashboard" } } - } - }, - "examples": [ - true, - "right", + }, + { + "url": "https://www.example.com/app", + "timeout": 60000, + "waitUntil": { + "networkIdleTime": null + } + }, { - "button": "left", - "elementText": "Element text" + "url": "https://www.example.com/status", + "waitUntil": { + "find": { + "elementText": "System operational" + } + } }, { - "selector": "#elementToScreenshot", - "elementText": "Element text", - "button": "middle" + "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": "click" + "title": "goTo" } ] }, { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", "required": [ - "find" + "httpRequest" ], "properties": { - "find": { + "httpRequest": { "$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.", + "title": "httpRequest", + "description": "Perform a generic HTTP request, for example to an API.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/string" + "title": "HTTP request (simple)", + "type": "string", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/components/schemas/object" - } - ], - "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": { + "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": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } + "type": "integer" } - ], - "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + ] }, - "elementAttribute": { - "type": "object", - "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", - "additionalProperties": { + "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": {} }, { - "type": "number" + "title": "Request body (array)", + "description": "JSON array to include as the body of the HTTP request.", + "type": "array", + "items": {} }, { - "type": "boolean" + "title": "Request body (string)", + "description": "String to include as the body of the HTTP request.", + "type": "string" } - ] + ], + "default": {} } }, - "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": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click" - }, - { - "type": "object", - "properties": { - "button": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/components/schemas/button" - } - }, - "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": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type" - }, - { - "not": { + "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", - "required": [ - "selector", - "elementText", - "elementId", - "elementTestId", - "elementClass", - "elementAttribute", - "elementAria" - ], - "title": "Find element and type" + "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" } - } - ] - } - } - } - } - }, - "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": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" - }, - { - "type": "object", - "required": [ - "goTo" - ], - "properties": { - "goTo": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "goTo", - "anyOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/string" - }, - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/3/allOf/1/properties/goTo/components/schemas/object" + ], + "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": { - "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.", + "url": { + "title": "HTTP request (simple)", "type": "string", - "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", "transform": [ "trim" ] }, "object": { - "description": "Navigate to an HTTP or HTTPS URL.", + "title": "HTTP request (detailed)", "type": "object", - "additionalProperties": false, - "required": [ - "url" + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } ], + "additionalProperties": false, "properties": { "url": { + "title": "HTTP request (simple)", "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_]+)", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", "transform": [ "trim" ] }, - "origin": { + "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": "Protocol and domain to navigate to. Prepended to `url`.", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], "transform": [ - "trim" - ] + "trim", + "toEnumCase" + ], + "default": "get" }, "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 + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 }, - "waitUntil": { + "request": { "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.", + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, "anyOf": [ { - "type": "integer", - "minimum": 0 + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} }, { - "type": "null" + "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" } - ], - "default": 500 + ] }, - "domIdleTime": { - "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "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": [ { - "type": "integer", - "minimum": 0 + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} }, { - "type": "null" + "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": 1000 - }, - "find": { + "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", - "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", - "additionalProperties": false, + "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": [ { - "required": [ - "selector" - ] - }, - { - "required": [ - "elementText" - ] - }, - { - "required": [ - "elementId" - ] - }, - { - "required": [ - "elementTestId" - ] - }, - { - "required": [ - "elementClass" - ] + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." }, { - "required": [ - "elementAttribute" - ] + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} }, { - "required": [ - "elementAria" - ] + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" } ], - "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." - } - } + "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" }, - "title": "Go to URL (detailed)" - } - } - }, - "examples": [ - "https://www.google.com", - "/search", + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } + }, + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } + }, + "statusCodes": [ + 200 + ] + }, { - "url": "https://www.google.com" + "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" }, { - "url": "/search", - "origin": "https://www.google.com" + "openApi": "getUserById" }, { - "url": "https://www.example.com", - "waitUntil": { - "networkIdleTime": 500 + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } } }, { - "url": "https://www.example.com/dashboard", - "waitUntil": { - "find": { - "selector": "[data-testid='dashboard-loaded']" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 } } }, { - "url": "https://www.example.com/app", - "timeout": 60000, - "waitUntil": { - "networkIdleTime": 500, - "domIdleTime": 1000, - "find": { - "selector": ".main-content", - "elementText": "Dashboard" - } + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" } }, { - "url": "https://www.example.com/app", - "timeout": 60000, - "waitUntil": { - "networkIdleTime": null + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" } }, { - "url": "https://www.example.com/status", - "waitUntil": { - "find": { - "elementText": "System operational" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" } } }, { - "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" + "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" } } } @@ -2218,241 +12908,228 @@ ] } }, - "title": "goTo" + "title": "httpRequest" } ] }, { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", "required": [ - "httpRequest" + "runShell" ], "properties": { - "httpRequest": { + "runShell": { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "httpRequest", - "description": "Perform a generic HTTP request, for example to an API.", + "title": "runShell", + "description": "Perform a native shell command.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", + "type": "string", + "transform": [ + "trim" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/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)" } ], "components": { "schemas": { - "url": { - "title": "HTTP request (simple)", + "string": { + "title": "Run shell command (simple)", + "description": "Command to perform in the machine's default shell.", "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" - ] - } + "required": [ + "command" ], "additionalProperties": false, "properties": { - "url": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/components/schemas/url" - }, - "openApi": { - "anyOf": [ - { - "allOf": [ - { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0/components/schemas/operationId" - }, - { - "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": [ - { - "$ref": "#/properties/integrations/properties/openApi/items/allOf/0" - }, - { - "type": "object", - "required": [ - "operationId" - ], - "title": "OpenAPI definition (httpRequest)" - } - ] - } - ] + "command": { + "type": "string", + "description": "Command to perform in the machine's default shell." }, - "statusCodes": { - "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.", + "args": { "type": "array", + "description": "Arguments for the command.", "items": { "anyOf": [ { - "type": "integer" + "type": "string" } ] }, - "default": [ - 200, - 201 - ] + "default": [] }, - "method": { + "workingDirectory": { "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" + "description": "Working directory for the command.", + "default": "." }, - "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": [] - } + "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" + } + ] }, - "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 + "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`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings." + "description": "File path to save the command's output, relative to `directory`." }, "directory": { "type": "string", @@ -2474,231 +13151,133 @@ "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": [ - "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" - } - } - }, + "docker run hello-world", { - "url": "https://reqres.in/api/users", - "method": "post", - "request": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "response": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "statusCodes": [ - 200, - 201 + "command": "echo", + "args": [ + "$USER" ] }, { - "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 + "command": "echo", + "args": [ + "hello-world" ] }, { - "url": "https://reqres.in/api/users", - "method": "post", - "request": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "response": { - "body": { - "name": "morpheus", - "job": "leader" - } - }, - "statusCodes": [ - 200, - 201 + "command": "docker run hello-world", + "timeout": 20000, + "exitCodes": [ + 0 ], - "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" - ] - } + "stdio": "Hello from Docker!" }, { - "url": "https://api.example.com/users/123", - "response": { - "required": [ - "user.profile.name", - "user.profile.avatar", - "user.settings.notifications" - ] - } + "command": "false", + "exitCodes": [ + 1 + ] }, { - "url": "https://api.example.com/orders", - "response": { - "required": [ - "orders[0].id", - "orders[0].total", - "orders[0].items[0].productId" - ] - } + "command": "echo", + "args": [ + "setup" + ], + "exitCodes": [ + 0 + ], + "stdio": "/.*?/" }, { - "url": "https://api.example.com/users", - "response": { - "required": [ - "sessionToken", - "expiresAt", - "user.id" - ], - "body": { - "status": "success", - "user": { - "role": "admin" - } - } - } + "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": "httpRequest" - } - ] - }, - { - "allOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" - }, - { - "type": "object", - "required": [ - "runShell" - ], - "properties": { - "runShell": { - "$ref": "#/properties/fileTypes/anyOf/0/items/anyOf/2/properties/runShell/anyOf/0" + }, + "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": "runShell" - } - ] - }, - { - "allOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + "title": "Common" }, { "type": "object", @@ -2712,7 +13291,92 @@ "description": "Assemble and run code.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/6/allOf/1/properties/runCode/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)" } ], "components": { @@ -2851,7 +13515,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -2865,10 +13584,108 @@ "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": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/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 } ], "components": { @@ -2897,7 +13714,23 @@ "type": "object", "properties": { "keys": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/7/allOf/1/properties/type/components/schemas/keys" + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } + ] }, "inputDelay": { "type": "number", @@ -2942,79 +13775,316 @@ { "type": "string" }, - { - "type": "number" + { + "type": "number" + }, + { + "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." }, - { - "type": "boolean" + "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." + } + ] } - ] + } } - }, - "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": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/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": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/path" - }, - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/object" + ] + } + }, + "title": "Capture screenshot (detailed)" }, { "type": "boolean", @@ -3038,7 +14108,13 @@ "additionalProperties": false, "properties": { "path": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/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" + ] }, "directory": { "type": "string", @@ -3072,7 +14148,134 @@ "description": "Display text or selector of the element to screenshot." }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/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." + } + ] + } + } } ] } @@ -3182,7 +14385,28 @@ "minimum": 0 }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/8/allOf/1/properties/screenshot/components/schemas/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." } ] } @@ -3258,7 +14482,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -3272,10 +14551,107 @@ "description": "Save a specific browser cookie to a file or environment variable for later reuse.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/9/allOf/1/properties/saveCookie/components/schemas/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)" } ], "components": { @@ -3422,7 +14798,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "type": "object", @@ -3436,10 +14867,42 @@ "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": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/10/allOf/1/properties/record/components/schemas/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)" }, { "type": "boolean", @@ -3489,25 +14952,80 @@ } } }, - "examples": [ - true, - "results.mp4", - { - "path": "results.mp4", - "directory": "static/media", - "overwrite": "true" + "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": "record" - } - ] - }, - { - "allOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + "title": "Common" }, { "type": "object", @@ -3537,7 +15055,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "loadVariables", @@ -3547,7 +15120,13 @@ ], "properties": { "loadVariables": { - "$ref": "#/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" + ] } } } @@ -3556,7 +15135,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "dragAndDrop", @@ -3576,12 +15210,222 @@ ], "properties": { "source": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", - "description": "The element to drag." + "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/elementSpecification", - "description": "The target location to drop the element." + "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", @@ -3595,10 +15439,108 @@ "elementSpecification": { "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/string" + "title": "Element (simple)", + "type": "string", + "description": "Display text, selector, or regex pattern (enclosed in forward slashes) of the element." }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/13/allOf/1/properties/dragAndDrop/components/schemas/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 + } + } } ] }, @@ -3751,16 +15693,71 @@ "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 } - } - } - ] - }, - { - "allOf": [ - { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/components/schemas/common" + }, + "title": "Common" }, { "title": "loadCookie", @@ -3775,10 +15772,101 @@ "description": "Load a specific cookie from a file or environment variable into the browser.", "anyOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/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" + ] }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/14/allOf/1/properties/loadCookie/components/schemas/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)" } ], "components": { @@ -3913,7 +16001,62 @@ { "allOf": [ { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/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" }, { "title": "wait", @@ -3933,7 +16076,12 @@ "title": "Wait (simple)" }, { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/15/allOf/1/properties/wait/components/schemas/string" + "title": "Wait (environment variable)", + "type": "string", + "pattern": "(\\$[A-Za-z0-9_]+)", + "transform": [ + "trim" + ] }, { "type": "boolean", @@ -4111,108 +16259,223 @@ } }, { - "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/0" - } + "find": "Find me!" }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/1" + "selector": "[title=Search]" } }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/2" + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" } }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/3" + "selector": "[title=Search]", + "click": { + "button": "right" + } } }, { "find": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/2/allOf/1/properties/find/examples/4" + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } } }, { - "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/0" - } + "click": true }, { - "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/1" - } + "click": "right" }, { "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/2" + "button": "left", + "elementText": "Element text" } }, { "click": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/1/allOf/1/properties/click/examples/3" + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" } }, { - "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/0" - } + "httpRequest": "https://reqres.in/api/users" }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/1" + "url": "https://reqres.in/api/users" } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/2" + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/3" + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/4" + "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/5" + "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": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/6" + "openApi": "getUserById" } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/7" + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/8" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/9" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/10" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } } }, { "httpRequest": { - "$ref": "#/components/schemas/markupDefinition/properties/actions/anyOf/1/items/anyOf/1/anyOf/4/allOf/1/properties/httpRequest/examples/11" + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } } }, { @@ -4298,7 +16561,10 @@ "description": "Nested matchers for child nodes. All child matchers must match at least one child.", "type": "array", "items": { - "$ref": "#/components/schemas/astNodeMatch" + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": {}, + "title": "AST node match configuration" } }, "extract": { @@ -4348,7 +16614,18 @@ "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": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -4356,7 +16633,18 @@ "description": "Regular expressions that indicate that the current test is complete.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -4364,7 +16652,18 @@ "description": "Regular expressions that indicates that the following content should be ignored for testing purposes.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -4372,7 +16671,18 @@ "description": "Regular expressions that indicate that the ignored section of content is complete.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] }, @@ -4380,7 +16690,18 @@ "description": "Regular expressions that indicate a step in a test.", "anyOf": [ { - "$ref": "#/components/schemas/stringOrArray" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + ] } ] } @@ -6175,123 +18496,387 @@ "type": "string" }, { - "type": "array", - "items": { - "type": "string" - } - } - ], - "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." - }, - "elementAttribute": { - "type": "object", - "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." + }, + "elementAttribute": { + "type": "object", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "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" + ] + } }, - { - "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 + "title": "Find element and click" + } + ] }, - "click": { - "description": "Click the element.", - "anyOf": [ + "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": "click", - "description": "Click or tap an element.", + "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": "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", + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", "anyOf": [ { - "required": [ - "selector" - ] - }, - { - "required": [ - "elementText" - ] - }, - { - "required": [ - "elementId" - ] - }, - { - "required": [ - "elementTestId" - ] - }, - { - "required": [ - "elementClass" - ] - }, - { - "required": [ - "elementAttribute" - ] + "type": "string" }, { - "required": [ - "elementAria" - ] + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } } - ], + ] + }, + { + "title": "Type keys (detailed)", + "type": "object", "properties": { - "button": { - "description": "Kind of click to perform.", - "type": "string", - "enum": [ - "left", - "right", - "middle" + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } ] }, - "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." + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 }, "selector": { "type": "string", - "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + "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 click. Supports exact match or regex pattern using /pattern/ syntax." + "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 click. Supports exact match or regex pattern using /pattern/ syntax." + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." }, "elementClass": { "anyOf": [ @@ -6328,93 +18913,77 @@ "type": "string", "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." } - } - }, - { - "type": "boolean" + }, + "required": [ + "keys" + ], + "additionalProperties": false } ], "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", + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", "anyOf": [ { - "required": [ - "selector" - ] - }, - { - "required": [ - "elementText" - ] - }, - { - "required": [ - "elementId" - ] - }, - { - "required": [ - "elementTestId" - ] - }, - { - "required": [ - "elementClass" - ] - }, - { - "required": [ - "elementAttribute" - ] + "type": "string" }, { - "required": [ - "elementAria" - ] + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } } - ], + ] + }, + "object": { + "title": "Type keys (detailed)", + "type": "object", "properties": { - "button": { - "description": "Kind of click to perform.", - "type": "string", - "enum": [ - "left", - "right", - "middle" + "keys": { + "title": "Type keys (simple)", + "description": "Sequence of keys to enter.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + } + ] + } + } ] }, - "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." + "inputDelay": { + "type": "number", + "description": "Delay in milliseconds between each key press during a recording", + "default": 100 }, "selector": { "type": "string", - "description": "Selector of the element to click. If combined with other element finding fields, the element must match all specified criteria." + "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 click. Supports exact match or regex pattern using /pattern/ syntax." + "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 click. Supports exact match or regex pattern using /pattern/ syntax." + "description": "data-testid attribute of the element to find. Supports exact match or regex pattern using /pattern/ syntax." }, "elementClass": { "anyOf": [ @@ -6451,52 +19020,412 @@ "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" + } + ] } }, - "examples": [ - true, - "right", + "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": [ { - "button": "left", - "elementText": "Element text" + "type": "integer", + "minimum": 0 }, { - "selector": "#elementToScreenshot", - "elementText": "Element text", - "button": "middle" + "type": "null" } - ] + ], + "default": 500 }, - { - "type": "object", - "properties": { - "button": { - "description": "Kind of click to perform.", - "type": "string", - "enum": [ - "left", - "right", - "middle" - ] + "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" } - }, - "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$`.", + ], + "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": [ { - "title": "Type keys (simple)", - "description": "Sequence of keys to enter.", + "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" @@ -6504,1413 +19433,10015 @@ { "type": "array", "items": { - "anyOf": [ - { - "type": "string" - } - ] + "type": "string" } } - ] + ], + "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." }, - { - "title": "Type keys (detailed)", + "elementAttribute": { "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.", + "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", + "additionalProperties": { "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" - } - ] - } + "type": "number" }, - "elementAria": { - "type": "string", - "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + { + "type": "boolean" } - }, - "required": [ - "keys" - ], - "additionalProperties": false + ] } - } - }, - "examples": [ - "kittens", - [ - "$ENTER$" - ], - [ - "kittens", - "$ENTER$" - ], - { - "keys": "kittens" - }, - { - "keys": [ - "$ENTER$" - ] }, - { - "keys": [ - "kittens", - "$ENTER$" - ], - "inputDelay": 500 + "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" ] }, { - "not": { - "type": "object", + "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": [ - "selector", - "elementText", - "elementId", - "elementTestId", - "elementClass", - "elementAttribute", - "elementAria" - ], - "title": "Find element and type" + "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": [ - "Find me!", - { - "selector": "[title=Search]" - }, + "session_token", + "./test-data/auth-session.txt", + "test_env_cookie", { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": "shorthair cat" + "name": "auth_cookie", + "variable": "AUTH_COOKIE" }, { - "selector": "[title=Search]", - "click": { - "button": "right" - } + "name": "test_cookie", + "path": "test-cookie.txt" }, { - "selector": "[title=Search]", - "timeout": 10000, - "elementText": "Search", - "moveTo": true, - "click": true, - "type": { - "keys": [ - "shorthair cat" - ], - "inputDelay": 100 - } + "name": "session_token", + "path": "session-token.txt", + "directory": "./test-data" }, { - "elementId": "/^user-[0-9]+$/", - "elementClass": [ - "admin", - "/^level-[1-5]$/" - ], - "elementAttribute": { - "data-active": true, - "data-score": "/^[0-9]+$/" - }, - "timeout": 8000, - "moveTo": false + "name": "user_session", + "path": "saved-cookies.txt", + "domain": "app.example.com" } ] }, - "goTo_v3": { + "loadVariables_v3": { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "goTo", + "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": "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.", + "title": "HTTP request (simple)", "type": "string", - "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", "transform": [ "trim" ] }, { - "description": "Navigate to an HTTP or HTTPS URL.", + "title": "HTTP request (detailed)", "type": "object", - "additionalProperties": false, - "required": [ - "url" + "anyOf": [ + { + "required": [ + "url" + ] + }, + { + "required": [ + "openApi" + ] + } ], + "additionalProperties": false, "properties": { "url": { + "title": "HTTP request (simple)", "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_]+)", + "description": "URL for the HTTP request.", + "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", "transform": [ "trim" ] }, - "origin": { + "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": "Protocol and domain to navigate to. Prepended to `url`.", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], "transform": [ - "trim" - ] + "trim", + "toEnumCase" + ], + "default": "get" }, "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 + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 }, - "waitUntil": { + "request": { "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.", + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, "anyOf": [ { - "type": "integer", - "minimum": 0 + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} }, { - "type": "null" + "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" } - ], - "default": 500 + ] }, - "domIdleTime": { - "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "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": [ { - "type": "integer", - "minimum": 0 + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} }, { - "type": "null" + "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": 1000 - }, - "find": { + "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", - "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", - "additionalProperties": false, + "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": [ { - "required": [ - "selector" - ] - }, - { - "required": [ - "elementText" - ] - }, - { - "required": [ - "elementId" - ] - }, - { - "required": [ - "elementTestId" - ] - }, - { - "required": [ - "elementClass" - ] + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." }, { - "required": [ - "elementAttribute" - ] + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} }, { - "required": [ - "elementAria" - ] + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" } ], - "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" + "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" + } }, - { - "type": "array", - "items": { - "type": "string" + "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." + } } - } - ], - "description": "Class or array of classes that the element must have. Each class supports exact match or regex pattern using /pattern/ syntax. Element must have all specified classes." - }, - "elementAttribute": { - "type": "object", - "description": "Object of attribute key-value pairs that the element must have. Values can be strings (supporting /pattern/ regex), numbers, or booleans. Boolean true matches attribute presence, false matches absence.", - "additionalProperties": { - "anyOf": [ + }, + "examples": [ { - "type": "string" + "descriptionPath": "https://petstore.swagger.io/v2/swagger.json" }, { - "type": "number" + "name": "Reqres", + "operationId": "getUserById" }, { - "type": "boolean" + "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)" } - }, - "elementAria": { - "type": "string", - "description": "Computed accessible name of the element per ARIA specification. Supports exact match or regex pattern using /pattern/ syntax." + ] + } + ] + }, + "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" } - } - } - } - } - }, - "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" + ] + }, + "default": [ + 200, + 201 ] }, - "origin": { + "method": { "type": "string", - "description": "Protocol and domain to navigate to. Prepended to `url`.", + "description": "Method of the HTTP request", + "enum": [ + "get", + "put", + "post", + "patch", + "delete" + ], "transform": [ - "trim" - ] + "trim", + "toEnumCase" + ], + "default": "get" }, "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 + "description": "Timeout for the HTTP request, in milliseconds.", + "default": 60000 }, - "waitUntil": { + "request": { "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.", + "headers": { + "description": "Headers to include in the HTTP request.", + "default": {}, "anyOf": [ { - "type": "integer", - "minimum": 0 + "title": "Request headers (object)", + "description": "Headers to include in the HTTP request, in key/value format.", + "type": "object", + "additionalProperties": true, + "properties": {} }, { - "type": "null" + "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" } - ], - "default": 500 + ] }, - "domIdleTime": { - "description": "Wait for DOM mutations to stop for this duration in milliseconds. Set to `null` to skip this check.", + "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": [ { - "type": "integer", - "minimum": 0 + "title": "Request body (object)", + "description": "JSON object to include as the body of the HTTP request.", + "type": "object", + "additionalProperties": true, + "properties": {} }, { - "type": "null" + "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": 1000 - }, - "find": { + "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", - "description": "Wait for a specific element to be present in the DOM. At least one of selector or elementText must be specified.", - "additionalProperties": false, + "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": [ { - "required": [ - "selector" - ] - }, - { - "required": [ - "elementText" - ] - }, - { - "required": [ - "elementId" - ] - }, - { - "required": [ - "elementTestId" - ] - }, - { - "required": [ - "elementClass" - ] + "type": "object", + "additionalProperties": true, + "properties": {}, + "title": "Response body object", + "description": "JSON key/value pairs expected in the response." }, { - "required": [ - "elementAttribute" - ] + "title": "Response body array", + "description": "JSON array expected in the response.", + "type": "array", + "items": {} }, { - "required": [ - "elementAria" - ] + "title": "Response body string", + "description": "String expected in the response.", + "type": "string" } ], - "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." - } - } + "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" } - }, - "title": "Go to URL (detailed)" + } } } }, "examples": [ - "https://www.google.com", - "/search", - { - "url": "https://www.google.com" - }, + "https://reqres.in/api/users", { - "url": "/search", - "origin": "https://www.google.com" + "url": "https://reqres.in/api/users" }, { - "url": "https://www.example.com", - "waitUntil": { - "networkIdleTime": 500 + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } } }, { - "url": "https://www.example.com/dashboard", - "waitUntil": { - "find": { - "selector": "[data-testid='dashboard-loaded']" + "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.example.com/app", - "timeout": 60000, - "waitUntil": { - "networkIdleTime": 500, - "domIdleTime": 1000, - "find": { - "selector": ".main-content", - "elementText": "Dashboard" + "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://www.example.com/app", - "timeout": 60000, - "waitUntil": { - "networkIdleTime": null - } + "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" }, { - "url": "https://www.example.com/status", - "waitUntil": { - "find": { - "elementText": "System operational" - } - } + "openApi": "getUserById" }, { - "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" - } + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 } } - } - ] - }, - "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" - ] + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 } - }, - "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" + } + }, + { + "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" ] - }, - "object": { - "type": "object", - "additionalProperties": false, + } + }, + { + "url": "https://api.example.com/users/123", + "response": { "required": [ - "name" - ], - "anyOf": [ - { - "required": [ - "path" - ], - "not": { - "required": [ - "variable" - ] - } - }, - { - "required": [ - "variable" - ], - "not": { - "anyOf": [ - { - "required": [ - "path" - ] - }, - { - "required": [ - "directory" - ] - } - ] - } - } + "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" ], - "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" - ] + "body": { + "status": "success", + "user": { + "role": "admin" } - }, - "title": "Load cookie (detailed)" + } } } - }, - "examples": [ - "session_token", - "./test-data/auth-session.txt", - "test_env_cookie", + ] + }, + "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": [ { - "name": "auth_cookie", - "variable": "AUTH_COOKIE" + "required": [ + "descriptionPath" + ] }, { - "name": "test_cookie", - "path": "test-cookie.txt" + "required": [ + "operationId" + ] + } + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the OpenAPI description, as defined in your configuration." }, - { - "name": "session_token", - "path": "session-token.txt", - "directory": "./test-data" + "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" }, - { - "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)", + "exampleKey": { "type": "string", - "description": "URL for the HTTP request.", - "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)", - "transform": [ - "trim" - ] + "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": "" }, - { - "title": "HTTP request (detailed)", + "headers": { "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)" - } - ] - } + "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" ] }, - "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" - } + "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" ] }, - "default": [ - 200, - 201 - ] + "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" + ] + } }, - "method": { + "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", - "description": "Method of the HTTP request", "enum": [ - "get", - "put", - "post", - "patch", - "delete" - ], - "transform": [ - "trim", - "toEnumCase" - ], - "default": "get" + "https://raw.githubusercontent.com/doc-detective/common/refs/heads/main/dist/schemas/config_v3.schema.json" + ] }, - "timeout": { - "type": "integer", - "description": "Timeout for the HTTP request, in milliseconds.", - "default": 60000 + "configId": { + "description": "Identifier for the configuration.", + "type": "string" }, - "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": {} - }, + "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": [ { - "title": "Request body (array)", - "description": "JSON array to include as the body of the HTTP request.", - "type": "array", - "items": {} + "type": "string" }, { - "title": "Request body (string)", - "description": "String to include as the body of the HTTP request.", - "type": "string" + "type": "array", + "minItems": 1, + "items": { + "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" + "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" }, - "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." + { + "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" + } + ] + } + } + ] + } }, - { - "title": "Response body array", - "description": "JSON array expected in the response.", - "type": "array", - "items": {} + "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" + } + } }, - { - "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" + "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": { - "anyOf": [ - { - "allOf": [ + } + }, + "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", - "description": "ID of the operation to use for the request." + "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", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} + }, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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": "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." + "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", @@ -8071,646 +29602,24608 @@ "headers": { "Authorization": "Bearer 12345" } - } - ] - }, - { - "type": "object", - "required": [ - "operationId" - ], - "title": "OpenAPI definition (httpRequest)" + } + ] + }, + { + "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" + } + }, + "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", + "anyOf": [ + { + "required": [ + "ast" + ] + }, + { + "required": [ + "regex" + ] + } + ], + "properties": { + "name": { + "description": "Name of the markup definition", + "type": "string" + }, + "ast": { + "description": "AST node matching configuration. When specified with regex, AST identifies candidate nodes first, then regex filters matched node content (AND operation).", + "type": "object", + "properties": { + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": { + "nodeType": {}, + "attributes": {}, + "content": {}, + "children": {}, + "extract": {} + }, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" + }, + { + "$1": "content" + } + ] + } + }, + "title": "AST node match configuration" + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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" + } + } + } + ] + } + ] + } } ] } - ] - }, - "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 + "title": "Markup definition" }, - "request": { + "astNodeMatch": { "type": "object", - "additionalProperties": false, + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", "properties": { - "headers": { - "description": "Headers to include in the HTTP request.", - "default": {}, + "nodeType": { + "description": "The type of AST node to match (e.g., 'code', 'element', 'listing'). Can be a string or array of strings.", "anyOf": [ { - "title": "Request headers (object)", - "description": "Headers to include in the HTTP request, in key/value format.", - "type": "object", - "additionalProperties": true, - "properties": {} + "type": "string" }, { - "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" + "type": "array", + "items": { + "type": "string" + } } ] }, - "parameters": { - "description": "URL parameters to include in the HTTP request, in key/value format.", + "attributes": { + "description": "Attribute matchers. Values can be: exact string, regex pattern (/pattern/), array of options (any-of), or boolean (true=exists, false=not exists).", "type": "object", - "additionalProperties": true, - "default": {}, - "properties": {}, - "title": "Request parameters" + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } }, - "body": { - "description": "The body of the HTTP request.", + "content": { + "description": "Pattern to match against the node's text content. Can be exact string or regex pattern.", "anyOf": [ { - "title": "Request body (object)", - "description": "JSON object to include as the body of the HTTP request.", - "type": "object", - "additionalProperties": true, - "properties": {} + "type": "string" }, { - "title": "Request body (array)", - "description": "JSON array to include as the body of the HTTP request.", - "type": "array", - "items": {} + "type": "boolean" + } + ] + }, + "children": { + "description": "Nested matchers for child nodes. All child matchers must match at least one child.", + "type": "array", + "items": { + "type": "object", + "description": "Configuration for matching AST nodes. Supports node type, attribute, content, and child matching.", + "properties": {}, + "title": "AST node match configuration" + } + }, + "extract": { + "description": "Maps capture group variables ($1, $2, etc.) to node paths for value extraction.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "$1": "attributes.lang", + "$2": "value" }, { - "title": "Request body (string)", - "description": "String to include as the body of the HTTP request.", - "type": "string" + "$1": "content" } - ], - "default": {} + ] } }, - "title": "Request" + "title": "AST node match configuration" }, - "response": { + "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", - "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" + "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" + } + } + ] + } + ] }, - "body": { - "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.", + "testEnd": { + "description": "Regular expressions that indicate that the current test is complete.", "anyOf": [ { - "type": "object", - "additionalProperties": true, - "properties": {}, - "title": "Response body object", - "description": "JSON key/value pairs expected in the response." - }, + "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": [ { - "title": "Response body array", - "description": "JSON array expected in the response.", - "type": "array", - "items": {} - }, + "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": [ { - "title": "Response body string", - "description": "String expected in the response.", - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "minItems": 1, + "items": { + "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" + "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" + } + } + ] } } - } - } - ] - }, - "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" + }, + "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 + }, + { + "fileTypes": [ + { + "extends": "markdown", + "extensions": [ + "md" + ], + "markup": [ + { + "name": "bashCodeBlock", + "ast": { + "nodeType": "code", + "attributes": { + "lang": [ + "bash", + "sh" + ] + }, + "extract": { + "$1": "attributes.lang", + "$2": "value" + } + }, + "actions": [ + { + "runCode": { + "language": "$1", + "code": "$2" + } + } + ] + } + ] + } + ] + }, + { + "fileTypes": [ + { + "extends": "dita", + "extensions": [ + "dita", + "xml" + ], + "markup": [ + { + "name": "ditaCodeblock", + "ast": { + "nodeType": "element", + "attributes": { + "tagName": "codeblock", + "outputclass": [ + "bash", + "shell" + ] + }, + "extract": { + "$1": "attributes.outputclass", + "$2": "content" + } + }, + "actions": [ + { + "runShell": { + "command": "$2" + } + } + ] + } + ] + } + ] + } ] - } - ], - "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." + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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." + } + ] + } + } + } + ] + } + }, + "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": [ { - "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" + "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 }, - "title": "Record (detailed)" - } - } - }, - "examples": [ - true, - "results.mp4", - { - "path": "results.mp4", - "directory": "static/media", - "overwrite": "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": [] + } + ] } ] }, From e66b149c9ceba1844ca5742d4386051f252e3ed5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:08:12 +0000 Subject: [PATCH 6/6] Optimize AST matching by pre-compiling regex patterns Co-authored-by: hawkeyexl <5209367+hawkeyexl@users.noreply.github.com> --- resolver/src/utils.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/resolver/src/utils.js b/resolver/src/utils.js index e23182f..9f8e1f5 100644 --- a/resolver/src/utils.js +++ b/resolver/src/utils.js @@ -552,13 +552,16 @@ async function parseContent({ config, content, filePath, fileType }) { if (astMatches.length > 0) { // If regex is also specified, filter AST matches by regex (AND operation) if (markup.regex && markup.regex.length > 0) { + // Pre-compile regex patterns for performance + const regexPatterns = (Array.isArray(markup.regex) ? markup.regex : [markup.regex]) + .map(pattern => new RegExp(pattern)); + astMatches.forEach((astMatch) => { const nodeContent = getNodeContent(astMatch.node); let regexMatched = false; let regexCaptures = {}; - for (const pattern of (Array.isArray(markup.regex) ? markup.regex : [markup.regex])) { - const regex = new RegExp(pattern); + for (const regex of regexPatterns) { const regexMatch = nodeContent.match(regex); if (regexMatch) { regexMatched = true;