From 78d8de89f4a0a8fc1c4cc32d183ad0e9ae30587b Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 13:46:30 -0700 Subject: [PATCH 01/31] Reference attempt one --- .scripts/buildSchemaReferences.js | 475 ++++++++++++++++---- docs/references/schemas/checkLink.md | 24 +- docs/references/schemas/click.md | 37 ++ docs/references/schemas/config.md | 515 +++------------------ docs/references/schemas/context.md | 136 ++++-- docs/references/schemas/find.md | 49 +- docs/references/schemas/goTo.md | 24 +- docs/references/schemas/httpRequest.md | 147 +++--- docs/references/schemas/loadVariables.md | 15 + docs/references/schemas/record.md | 30 ++ docs/references/schemas/runCode.md | 46 +- docs/references/schemas/runShell.md | 58 +-- docs/references/schemas/saveScreenshot.md | 93 ---- docs/references/schemas/screenshot.md | 71 +++ docs/references/schemas/setVariables.md | 22 - docs/references/schemas/specification.md | 171 ++++--- docs/references/schemas/startRecording.md | 39 -- docs/references/schemas/step.md | 517 ++++++++++++++++++++++ docs/references/schemas/stopRecord.md | 15 + docs/references/schemas/stopRecording.md | 20 - docs/references/schemas/test.md | 195 ++++---- docs/references/schemas/typeKeys.md | 32 +- docs/references/schemas/wait.md | 19 +- package-lock.json | 81 ++-- package.json | 10 +- 25 files changed, 1651 insertions(+), 1190 deletions(-) create mode 100644 docs/references/schemas/click.md create mode 100644 docs/references/schemas/loadVariables.md create mode 100644 docs/references/schemas/record.md delete mode 100644 docs/references/schemas/saveScreenshot.md create mode 100644 docs/references/schemas/screenshot.md delete mode 100644 docs/references/schemas/setVariables.md delete mode 100644 docs/references/schemas/startRecording.md create mode 100644 docs/references/schemas/step.md create mode 100644 docs/references/schemas/stopRecord.md delete mode 100644 docs/references/schemas/stopRecording.md diff --git a/.scripts/buildSchemaReferences.js b/.scripts/buildSchemaReferences.js index c2ba6b95..57a791a6 100644 --- a/.scripts/buildSchemaReferences.js +++ b/.scripts/buildSchemaReferences.js @@ -11,25 +11,27 @@ main(); async function main() { const schemasToGenerate = [ - "checkLink_v2", - "config_v2", - "context_v2", - "find_v2", - "goTo_v2", - "httpRequest_v2", - "runShell_v2", - "runCode_v2", - "saveScreenshot_v2", - "setVariables_v2", - "startRecording_v2", - "stopRecording_v2", - "spec_v2", - "test_v2", - "typeKeys_v2", - "wait_v2", + "checkLink_v3", + "click_v3", + "config_v3", + "context_v3", + "find_v3", + "goTo_v3", + "httpRequest_v3", + "runShell_v3", + "runCode_v3", + "screenshot_v3", + "loadVariables_v3", + "record_v3", + "stopRecord_v3", + "spec_v3", + "step_v3", + "test_v3", + "type_v3", + "wait_v3", ]; for await (const key of schemasToGenerate) { - schema = schemas[key]; + let schema = schemas[key]; // Dereference schema schema = await parser.dereference(schema); // Format @@ -41,10 +43,42 @@ async function main() { "Field | Type | Description | Default", ":-- | :-- | :-- | :--", ]; - const keys = Object.keys(schema.properties); - for (const key in keys) { - let field = keys[key]; - let fieldDetails = parseField(schema, field); + + // Extract all unique top-level property keys, handling direct properties, anyOf/oneOf, and allOf structures + const propertyKeys = new Set(); + + // Handle direct properties if they exist + if (schema.properties) { + Object.keys(schema.properties).forEach(key => propertyKeys.add(key)); + } + + // Handle polymorphic schemas with anyOf or oneOf + if (schema.anyOf || schema.oneOf) { + const variants = schema.anyOf || schema.oneOf; + + for (const variant of variants) { + // Check for properties directly within the variant + if (variant.properties) { + Object.keys(variant.properties).forEach(key => propertyKeys.add(key)); + } + // Check for properties within an allOf structure inside the variant + if (variant.allOf) { + for (const allOfItem of variant.allOf) { + if (allOfItem.properties) { + Object.keys(allOfItem.properties).forEach(key => propertyKeys.add(key)); + } + } + } + } + } + + // Get the unique keys as an array + const keys = Array.from(propertyKeys); + + // Process each top-level property + for (const field of keys) { // Changed loop variable name for clarity + // let field = keys[key]; // Old line + let fieldDetails = parseField(schema, field); // Pass only the top-level field name fields = fields.concat(fieldDetails); } fields.push(""); @@ -95,9 +129,46 @@ function parseField(schema, fieldName, fieldNameBase) { } else { name = fieldName; } - let property = schema.properties[fieldName]; + + // Find the property definition, handling direct properties, anyOf/oneOf, and allOf structures + let property; + + // Check direct properties first + if (schema.properties && schema.properties[fieldName]) { + property = schema.properties[fieldName]; + } + // If not found, check in anyOf/oneOf variants + else if (schema.anyOf || schema.oneOf) { + const variants = schema.anyOf || schema.oneOf; + + // Look for the property in each variant + for (const variant of variants) { + // Check direct properties within the variant + if (variant.properties && variant.properties[fieldName]) { + property = variant.properties[fieldName]; + break; // Found it + } + // Check within an allOf structure inside the variant + if (variant.allOf) { + for (const allOfItem of variant.allOf) { + if (allOfItem.properties && allOfItem.properties[fieldName]) { + property = allOfItem.properties[fieldName]; + break; // Found it + } + } + } + if (property) break; // Found it in the inner loop + } + } + + // If property still not found, handle the error + if (!property) { + console.warn(`Warning: Property '${fieldName}' not found in schema '${schema.title || 'unknown'}' or its variants`); + return [`${name} | unknown | Property definition not found | `]; + } + let typeDetails = getTypes(property); - let description = property.description; + let description = property.description || "No description provided."; // Get required if (schema.required && schema.required.includes(fieldName)) { description = "Required. " + description; @@ -148,19 +219,31 @@ function parseField(schema, fieldName, fieldNameBase) { // Parse child objects // Check if has child properties if (typeDetails.type === "object") { - let childProperties; + let childProperties = []; if (property.properties) childProperties = [property.properties]; if (property.anyOf || property.oneOf) { let xOfArray = property.anyOf || property.oneOf; - childProperties = xOfArray.filter((item) => item.property); + // Improved filtering for polymorphic objects + let polymorphicObjects = xOfArray.filter((item) => + item.properties || (item.type === "object" && item.title) + ); + + // Add each variant's properties to childProperties + for (const obj of polymorphicObjects) { + if (obj.properties) childProperties.push(obj.properties); + } } + + // Process all child properties for (const prop in childProperties) { property.properties = childProperties[prop]; - const keys = Object.keys(property.properties); - for (const key in keys) { - let field = keys[key]; - let fieldDetails = parseField(property, field, name); - for (const detail in fieldDetails) details.push(fieldDetails[detail]); + if (property.properties) { + const keys = Object.keys(property.properties); + for (const key in keys) { + let field = keys[key]; + let fieldDetails = parseField(property, field, name); + for (const detail in fieldDetails) details.push(fieldDetails[detail]); + } } } } @@ -169,7 +252,7 @@ function parseField(schema, fieldName, fieldNameBase) { let itemsArray = getItems(property, "object"); for (const index in itemsArray) { const item = itemsArray[index]; - if (item.type === "object" && !item.title) { + if (item.type === "object" && !item.title && item.properties) { // console.log(item); const keys = Object.keys(item.properties); for (const key in keys) { @@ -185,47 +268,110 @@ function parseField(schema, fieldName, fieldNameBase) { } function getItems(property, typeFilter) { - let items; - if (property.items && (property.items.anyOf || property.items.oneOf)) { - items = property.items.anyOf || property.items.oneOf; - } else if (property.items) { - items = [property.items]; + let items = []; + + // Handle direct items property + if (property.items) { + if (property.items.anyOf || property.items.oneOf) { + // Array items with polymorphic types + items = property.items.anyOf || property.items.oneOf; + } else { + // Single type array items + items = [property.items]; + } } - if ( - (property.anyOf && property.anyOf.items) || - (property.oneOf && property.oneOf.items) - ) { - items = property.anyOf.items || property.oneOf.items; + + // Handle items in anyOf/oneOf variants + if (property.anyOf || property.oneOf) { + const variants = property.anyOf || property.oneOf; + + // Collect items from all variants that have them + for (const variant of variants) { + if (variant.items) { + if (variant.items.anyOf || variant.items.oneOf) { + // Add all polymorphic items + const variantItems = variant.items.anyOf || variant.items.oneOf; + items = items.concat(variantItems); + } else { + // Add single item + items.push(variant.items); + } + } + } } - if (typeFilter) items = items.filter((item) => item.type === typeFilter); + + // Apply type filter if specified + if (typeFilter && items.length > 0) { + items = items.filter((item) => item.type === typeFilter); + } + return items; } function getTypes(property) { - // TODO: Include supported subtypes within array let type; let types = []; + // Get types if (!property.type && (property.anyOf || property.oneOf)) { - xOfArray = property.anyOf || property.oneOf; - types = xOfArray.filter((xOf) => xOf.type); + // Handle polymorphic properties with anyOf or oneOf + const xOfArray = property.anyOf || property.oneOf; + const typesArray = xOfArray.filter((xOf) => xOf.type || xOf.title); + + // Extract type information from each variant + types = typesArray.map(item => { + if (item.type) return item.type; + if (item.title) return "object"; + return "unknown"; + }); + if (types.length > 1) { + // Format for multiple type options type = "One of"; - for (const item of types) { - type = type + `
- ${item.type}`; - if (item.type === "array") { - subTypes = getArraySubTypes(item, 1); + for (const index in typesArray) { + const item = typesArray[index]; + const itemType = types[index]; + + // Basic type display + type = type + `
- ${itemType}`; + + // Add title for referenced objects + if (item.title) { + type = type + `([${item.title}](/docs/references/schemas/${item.title}))`; + } + + // Handle array subtypes + if (itemType === "array") { + const subTypes = getArraySubTypes(item, 1); type = type + subTypes; } } - } else { + } else if (types.length === 1) { + // Single type from oneOf/anyOf type = types[0]; + + // Add title for referenced objects + const item = typesArray[0]; + if (item.title) { + type = type + `([${item.title}](/docs/references/schemas/${item.title}))`; + } + + // Handle array subtypes + if (type === "array") { + const subTypes = getArraySubTypes(item, 0); + type = type + subTypes; + } + } else { + type = "unknown"; } } else if (property.type) { + // Direct type definition type = property.type; types = [type]; + + // Handle array subtypes if (type === "array") { - subTypes = getArraySubTypes(property, 0); + const subTypes = getArraySubTypes(property, 0); type = type + subTypes; } } @@ -236,23 +382,79 @@ function getTypes(property) { function getArraySubTypes(property, depth) { let subTypes = " of "; let itemsArray = getItems(property); + + // If no items found + if (!itemsArray || itemsArray.length === 0) { + return " of any"; + } + + // For multiple item types (polymorphic array) if (itemsArray.length > 1) { let spaces = ""; if (Number(depth) === 1) spaces = "  "; + + subTypes += "
" + spaces + "one of:"; + for (const index in itemsArray) { - item = itemsArray[index]; + const item = itemsArray[index]; + // Handle referenced schema objects if (item.type === "object" && item.title) { subTypes = `${subTypes}
${spaces}- ${item.type}([${item.title}](/docs/references/schemas/${item.title}))`; - } else { - subTypes = `${subTypes}
${spaces}- ${item.type}s`; + } + // Handle nested oneOf/anyOf in array items + else if (!item.type && (item.oneOf || item.anyOf)) { + const nestedTypes = (item.oneOf || item.anyOf) + .map(variant => { + if (variant.type === "object" && variant.title) { + return `${variant.type}([${variant.title}](/docs/references/schemas/${variant.title}))`; + } else if (variant.type) { + return variant.type; + } else { + return "unknown"; + } + }) + .join(", "); + subTypes = `${subTypes}
${spaces}- one of: ${nestedTypes}`; + } + // Handle regular types + else if (item.type) { + subTypes = `${subTypes}
${spaces}- ${item.type}`; + } + // Handle unknown types + else { + subTypes = `${subTypes}
${spaces}- unknown`; } } - } else { - item = itemsArray[0]; + } + // For single item type + else { + const item = itemsArray[0]; + // Handle referenced schema objects if (item.type === "object" && item.title) { subTypes = `${subTypes}${item.type}([${item.title}](/docs/references/schemas/${item.title}))`; - } else { - subTypes = subTypes + item.type + "s"; + } + // Handle nested oneOf/anyOf in array items + else if (!item.type && (item.oneOf || item.anyOf)) { + subTypes += "one of: "; + const variants = item.oneOf || item.anyOf; + const variantTypes = variants.map(variant => { + if (variant.type === "object" && variant.title) { + return `${variant.type}([${variant.title}](/docs/references/schemas/${variant.title}))`; + } else if (variant.type) { + return variant.type; + } else { + return "unknown"; + } + }).join(", "); + subTypes += variantTypes; + } + // Handle regular types + else if (item.type) { + subTypes += item.type; + } + // Handle unknown types + else { + subTypes += "unknown"; } } @@ -263,10 +465,30 @@ function getArraySubTypes(property, depth) { function getSchemaFormat(schema, depth) { let format = ["{"]; if (!depth) depth = 1; - // console.log(Object.keys(schema.properties)); - // exit() - let properties = schema.properties; - for (const [key, value] of Object.entries(properties)) { + + // Handle properties from multiple sources + let allProperties = {}; + + // Handle direct properties if they exist + if (schema.properties) { + allProperties = { ...schema.properties }; + } + + // Handle polymorphic schemas with anyOf or oneOf + if (schema.anyOf || schema.oneOf) { + const variants = schema.anyOf || schema.oneOf; + + // Extract properties from each variant that has them + for (const variant of variants) { + if (variant.properties) { + // Merge properties from this variant + allProperties = { ...allProperties, ...variant.properties }; + } + } + } + + // Process all properties + for (const [key, value] of Object.entries(allProperties)) { console.log({ key, value }); const typeDetails = getTypes(value); console.log(typeDetails.types); @@ -296,34 +518,117 @@ function getSchemaFormat(schema, depth) { return format; } -// TODO: Figure out formatting for oneOfs with arrays/objects function getFormatDescription(name, property, depth) { let description = []; if (!depth) depth = 1; - if (property.type === "object" && property.title) { - description.push(`${" ".repeat(depth)}"${name}": {`); - depth = depth + 1; + const indent = " ".repeat(depth); + + // Handle polymorphic properties (oneOf/anyOf) + if (!property.type && (property.oneOf || property.anyOf)) { + const variants = property.oneOf || property.anyOf; + description.push(`${indent}"${name}": /* One of the following: */`); + + // Add variants as comments + for (const variant of variants) { + if (variant.type === "object" && variant.title) { + description.push(`${indent}/* - object: ${variant.title} schema */`); + } else if (variant.type === "array") { + const itemTypes = getArrayItemType(variant); + description.push(`${indent}/* - array of ${itemTypes} */`); + } else if (variant.type) { + description.push(`${indent}/* - ${variant.type} */`); + } + } + + // Use the first variant for the example + const firstVariant = variants[0]; + if (firstVariant.type === "object" && firstVariant.title) { + description.push(`${indent}{`); + description.push(`${indent} /* See ${firstVariant.title} schema */`); + description.push(`${indent}},`); + } else if (firstVariant.type === "object") { + description.push(`${indent}{`); + description.push(`${indent} /* Object with custom properties */`); + description.push(`${indent}},`); + } else if (firstVariant.type === "array") { + const itemTypes = getArrayItemType(firstVariant); + description.push(`${indent}[ /* Array of ${itemTypes} */ ],`); + } else if (firstVariant.type === "string" && firstVariant.const) { + description.push(`${indent}"${firstVariant.const}",`); + } else if (firstVariant.type) { + description.push(`${indent}${firstVariant.type},`); + } else { + description.push(`${indent}/* Complex polymorphic type */,`); + } + } + // Handle object with title reference + else if (property.type === "object" && property.title) { + description.push(`${indent}"${name}": {`); description.push( - `${" ".repeat(depth)}object([${property.title}](/docs/references/schemas/${ - property.title - }))` + `${indent} /* See ${property.title} schema */` ); - depth = depth - 1; - description.push(`${" ".repeat(depth)}},`); - } else if (property.type === "object" && !property.title) { - description.push(`${" ".repeat(depth)}"${name}": {`); - depth = depth + 1; - description.push(`${" ".repeat(depth)}object`); - depth = depth - 1; - description.push(`${" ".repeat(depth)}},`); - } else if (property.type === "array") { - description.push(`${" ".repeat(depth)}"${name}": [ ${property.type} ],`); - } else if (property.type === "string" && property.const) { - description.push(`${" ".repeat(depth)}"${name}": "${property.const}",`); + description.push(`${indent}},`); + } + // Handle regular object + else if (property.type === "object" && !property.title) { + description.push(`${indent}"${name}": {`); + description.push(`${indent} /* Object with custom properties */`); + description.push(`${indent}},`); + } + // Handle array + else if (property.type === "array") { + const itemTypes = getArrayItemType(property); + description.push(`${indent}"${name}": [ /* Array of ${itemTypes} */ ],`); + } + // Handle string constants + else if (property.type === "string" && property.const) { + description.push(`${indent}"${name}": "${property.const}",`); + } + // Handle string enums + else if (property.type === "string" && property.enum) { + const enumValues = property.enum.map(val => `"${val}"`).join(" | "); + description.push(`${indent}"${name}": /* One of: ${enumValues} */,`); + } + // Handle other types + else if (property.type) { + description.push(`${indent}"${name}": ${property.type},`); + } + // Handle unknown types + else { + description.push(`${indent}"${name}": /* Unknown type */,`); + } + + return description.join("\n"); +} + +// Helper function to get array item type description +function getArrayItemType(property) { + const items = getItems(property); + if (!items || items.length === 0) { + return "any"; + } + + if (items.length === 1) { + const item = items[0]; + if (item.type === "object" && item.title) { + return `${item.title} objects`; + } else if (item.type) { + return `${item.type}s`; + } else if (item.oneOf || item.anyOf) { + const variants = item.oneOf || item.anyOf; + const types = variants.map(v => { + if (v.type === "object" && v.title) return v.title; + return v.type || "unknown"; + }).join(" | "); + return `[${types}]`; + } } else { - description.push(`${" ".repeat(depth)}"${name}": ${property.type},`); + const types = items.map(item => { + if (item.type === "object" && item.title) return item.title; + return item.type || "unknown"; + }).join(" | "); + return `[${types}]`; } - console.log(description); - description = description.join("\n"); - return description; + + return "unknown"; } diff --git a/docs/references/schemas/checkLink.md b/docs/references/schemas/checkLink.md index 4e774f3a..3a5460f1 100644 --- a/docs/references/schemas/checkLink.md +++ b/docs/references/schemas/checkLink.md @@ -1,41 +1,35 @@ # checkLink -Check if a URL returns an acceptable status code from a GET request. + ## Fields Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. Action to perform. | -url | string | Required. URL to check. | +url | string | Optional. URL to check. Can be a full URL or a path. If a path is provided, `origin` must be specified. | origin | string | Optional. Protocol and domain to navigate to. Prepended to `url`. | -statusCodes | array of integers | Optional. Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. | ``[200,201,202]`` +statusCodes | One of
- integer
- array of integer | Optional. Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. | ``[200,301,302,307,308]`` ## Examples ```json -{ - "action": "checkLink", - "url": "https://www.google.com" -} +"https://www.google.com" +``` + +```json +"/search" ``` ```json { - "action": "checkLink", "url": "https://www.google.com", - "statusCodes": [ - 200 - ] + "statusCodes": 200 } ``` ```json { - "action": "checkLink", "url": "/search", "origin": "www.google.com", "statusCodes": [ diff --git a/docs/references/schemas/click.md b/docs/references/schemas/click.md new file mode 100644 index 00000000..dce20c57 --- /dev/null +++ b/docs/references/schemas/click.md @@ -0,0 +1,37 @@ + +# click + +Click or tap an element. + +## Fields + +Field | Type | Description | Default +:-- | :-- | :-- | :-- +button | string | Optional. Kind of click to perform.

Accepted values: `left`, `right`, `middle` | +elementText | string | Optional. Display text of the element to click. If combined with `selector`, the element must match both the text and the selector. | +selector | string | Optional. Selector of the element to click. If combined with `elementText`, the element must match both the text and the selector. | + +## Examples + +```json +true +``` + +```json +"right" +``` + +```json +{ + "button": "left", + "elementText": "Element text" +} +``` + +```json +{ + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" +} +``` diff --git a/docs/references/schemas/config.md b/docs/references/schemas/config.md index abeaa424..257711d7 100644 --- a/docs/references/schemas/config.md +++ b/docs/references/schemas/config.md @@ -7,53 +7,24 @@ Configuration options for Doc Detective operations. Field | Type | Description | Default :-- | :-- | :-- | :-- -defaultCommand | string | Optional. Default command to run when no command is specified.

Accepted values: `runTests`, `runCoverage` | -input | One of
- string
- array of strings | Optional. Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files. | `.` -output | string | Optional. Path of the of the file or directory in which to store the output of Doc Detective commands. If a file path is specified, the output is written to that file. If a file of that name already exists, Doc Detective creates appends an integer to the result file name. If a directory path is specified, the output file name is dependent on the command being run. | `.` -recursive | boolean | Optional. If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specificaions and source files. | `true` -relativePathBase | string | Optional. Whether paths should be interpreted as relative to the current working directory (`cwd`) or to the file in which they're specified (`file`).

Accepted values: `cwd`, `file` | `cwd` -envVariables | string | Optional. Path to a `.env` file to load before performing a Doc Detective operation. | -runTests | object | Optional. Options for running tests. When running tests, values set here override general configuration options. | -runTests.input | One of
- string
- array of strings | Optional. Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files. | -runTests.output | string | Optional. Path of the of the file or directory in which to store the output of Doc Detective commands. If a file path is specified, the output is written to that file. If a file of that name already exists, Doc Detective creates appends an integer to the result file name. If a directory path is specified, the output file name is dependent on the command being run. | `.` -runTests.setup | One of
- string
- array of strings | Optional. Path(s) to test specifications to perform before those specified by `input`. Useful for setting up testing environments. | -runTests.cleanup | One of
- string
- array of strings | Optional. Path(s) to test specifications to perform after those specified by `input`. Useful for cleaning up testing environments. | -runTests.recursive | boolean | Optional. If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specificaions and source files. | -runTests.detectSteps | boolean | Optional. Whether or not to detect steps in input files based on markup regex. | `false` -runTests.mediaDirectory | string | Optional. DEPRECATED. | `.` -runTests.downloadDirectory | string | Optional. Path of the directory in which to store downloaded files. | `.` -runTests.contexts | array of object([context](/docs/references/schemas/context)) | Optional. Application/platform sets to run tests in. If no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. | ``[{"app":{"name":"firefox","options":{"width":1200,"height":800,"headless":true}},"platforms":["linux","mac","windows"]}]`` -runCoverage | object | Optional. Options for performing test coverage analysis on documentation source files. When performing coveration analysis, values set here override general configuration options. | -runCoverage.input | One of
- string
- array of strings | Optional. Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files. | -runCoverage.output | string | Optional. Path of the of the file or directory in which to store the output of Doc Detective commands. If a file path is specified, the output is written to that file. If a file of that name already exists, Doc Detective creates appends an integer to the result file name. If a directory path is specified, the output file name is dependent on the command being run. | `.` -runCoverage.recursive | boolean | Optional. If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specificaions and source files. | -runCoverage.markup | array of strings | Optional. Markup types to include when performing this operation. If no markup types are specified, the operation includes all markup types as defined in `fileTypes`. | ``["onscreenText","emphasis","image","hyperlink","codeInline","codeBlock","interaction"]`` -suggestTests | object | Optional. Options for suggesting tests based on documentation source files. When suggesting tests, values set here override general condiguration options. | -suggestTests.input | One of
- string
- array of strings | Optional. Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files. | -suggestTests.output | string | Optional. Path of the of the file or directory in which to store the output of Doc Detective commands. If a file path is specified, the output is written to that file. If a file of that name already exists, Doc Detective creates appends an integer to the result file name. If a directory path is specified, the output file name is dependent on the command being run. | `.` -suggestTests.recursive | boolean | Optional. If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specificaions and source files. | -suggestTests.markup | array of strings | Optional. Markup types to include when performing this operation. If no markup types are specified, the operation includes all markup types as defined in `fileTypes`. | ``["onscreenText","emphasis","image","hyperlink","codeInline","codeBlock","interaction"]`` -fileTypes | array of objects | Optional. Information on supported file types and how to parse the markup within them. | [] -fileTypes.name | string | Optional. Name of the file type. | -fileTypes.extensions | array of strings | Required. File extensions to support with this configuration. | -fileTypes.testStartStatementOpen | string | Required. Opening of an in-document test start statement. | -fileTypes.testStartStatementClose | string | Required. Close of an in-document test start statement. | -fileTypes.testIgnoreStatement | string | Required. Text for an in-document test ignore statement. | -fileTypes.testEndStatement | string | Required. Text for an in-document test end statement. | -fileTypes.stepStatementOpen | string | Required. Opening of an in-document step statement. | -fileTypes.stepStatementClose | string | Required. Close of an in-document step statement. | -fileTypes.markup | array of objects | Required. Markup types and associated regex patterns to find in documentation source files. | -fileTypes.markup.name | string | Required. Name of the markup type. | -fileTypes.markup.regex | array of strings | Required. Regex patterns to find the markup type in documentation source files. | -fileTypes.markup.actions | array of
- strings
- objects
- object([checkLink](/docs/references/schemas/checkLink))
- object([find](/docs/references/schemas/find))
- object([goTo](/docs/references/schemas/goTo))
- object([httpRequest](/docs/references/schemas/httpRequest))
- object([runShell](/docs/references/schemas/runShell))
- object([saveScreenshot](/docs/references/schemas/saveScreenshot))
- object([setVariables](/docs/references/schemas/setVariables))
- object([startRecording](/docs/references/schemas/startRecording))
- object([stopRecording](/docs/references/schemas/stopRecording))
- object([typeKeys](/docs/references/schemas/typeKeys))
- object([wait](/docs/references/schemas/wait)) | Optional. Actions that apply to the markup type. | -fileTypes.markup.actions.name | string | Required. Name of the action.

Accepted values: `checkLink`, `find`, `goTo`, `httpRequest`, `runShell`, `saveScreenshot`, `setVariables`, `startRecording`, `stopRecording`, `typeKeys`, `wait` | -fileTypes.markup.actions.params | object | Optional. Parameters for the action. | +configId | string | Optional. Identifier for the configuration. | Generated UUID +input | unknown | Optional. Path(s) to test specifications and documentation source files. May be paths to specific files or to directories to scan for files. | `.` +output | string | Optional. 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. | `.` +recursive | boolean | Optional. If `true` searches `input`, `setup`, and `cleanup` paths recursively for test specifications and source files. | `true` +relativePathBase | string | Optional. Whether paths should be interpreted as relative to the current working directory (`cwd`) or to the file in which they're specified (`file`).

Accepted values: `cwd`, `file` | `file` +loadVariables | string | Optional. Load environment variables from the specified `.env` file. | +origin | string | Optional. Default protocol and domain to use for relative URLs. | +beforeAny | One of
- string
- array of string | Optional. Path(s) to test specifications to perform before those specified by `input`. Useful for setting up testing environments. | +afterAll | One of
- string
- array of string | Optional. Path(s) to test specifications to perform after those specified by `input`. Useful for cleaning up testing environments. | +detectSteps | boolean | Optional. Whether or not to detect steps in input files based on defined markup. | `true` +logLevel | string | Optional. Amount of detail to output when performing an operation.

Accepted values: `silent`, `error`, `warning`, `info`, `debug` | `info` +runOn | array of object([context](/docs/references/schemas/context)) | Optional. Contexts to run the test in. Overrides contexts defined at the config and spec levels. | +fileTypes | array of
one of:
- string
- object([Custom](/docs/references/schemas/Custom))
- object([Executable](/docs/references/schemas/Executable)) | Optional. Configuration for file types and their markup detection. | [] integrations | object | Optional. Options for connecting to external services. | -integrations.openApi | array of undefineds | Optional. undefined | +integrations.openApi | array of unknown | Optional. No description provided. | telemetry | object | Optional. Options around sending telemetry for Doc Detective usage. | ``{"send":true}`` telemetry.send | boolean | Required. If `true`, sends Doc Detective telemetry. | `true` telemetry.userId | string | Optional. Identifier for the organization, group, or individual running Doc Detective. | -logLevel | string | Optional. Amount of detail to output when performing an operation.

Accepted values: `silent`, `error`, `warning`, `info`, `debug` | `info` ## Examples @@ -63,451 +34,77 @@ logLevel | string | Optional. Amount of detail to output when performing an ope ```json { - "input": ".", - "output": "." -} -``` - -```json -{ - "defaultCommand": "runTests", - "envVariables": "", "input": ".", "output": ".", "recursive": true, - "logLevel": "info", - "runTests": { - "input": ".", - "output": ".", - "setup": "", - "cleanup": "", - "recursive": true, - "downloadDirectory": ".", - "contexts": [ - { - "app": { - "name": "firefox", - "path": "" - }, - "platforms": [ - "linux", - "mac", - "windows" - ] - } - ] - } -} -``` - -```json -{ - "integrations": { - "openApi": [ - { - "name": "Acme", - "descriptionPath": "https://www.acme.com/openapi.json", - "server": "https://api.acme.com", - "mockResponse": true - } - ] - } + "loadVariables": ".env", + "fileTypes": [ + "markdown" + ] } ``` ```json { - "envVariables": "", - "input": ".", - "output": ".", - "recursive": true, - "logLevel": "info", - "runTests": { - "input": ".", - "output": ".", - "setup": "", - "cleanup": "", - "recursive": true, - "downloadDirectory": ".", - "contexts": [ - { - "app": { - "name": "firefox", - "path": "" - }, - "platforms": [ - "linux", - "mac", - "windows" - ] - } - ] - }, - "runCoverage": { - "recursive": true, - "input": ".", - "output": ".", - "markup": [] - }, "fileTypes": [ { - "name": "Markdown", + "extends": "markdown", "extensions": [ - ".md", - ".markdown", - ".mdx" + "md", + "markdown", + "mdx" ], - "testStartStatementOpen": "[comment]: # (test start", - "testStartStatementClose": ")", - "testIgnoreStatement": "[comment]: # (test ignore)", - "testEndStatement": "[comment]: # (test end)", - "stepStatementOpen": "[comment]: # (step", - "stepStatementClose": ")", + "inlineStatements": { + "testStart": "", + "testEnd": "", + "ignoreStart": "", + "ignoreEnd": "", + "step": "" + }, "markup": [ { "name": "onscreenText", - "regex": [ - "\\*\\*.+?\\*\\*" - ], - "actions": [ - "find" - ] - }, - { - "name": "emphasis", - "regex": [ - "(?", - "testIgnoreStatement": "", - "testEndStatement": "", - "stepStatementOpen": "", - "markup": [] + "name": "Python", + "extensions": "py", + "runShell": { + "command": "python $1" + } } - ], - "integrations": {}, - "telemetry": { - "send": true, - "userId": "Doc Detective" - } + ] } ``` diff --git a/docs/references/schemas/context.md b/docs/references/schemas/context.md index 2b6f168c..de93e2d0 100644 --- a/docs/references/schemas/context.md +++ b/docs/references/schemas/context.md @@ -1,92 +1,134 @@ # context -An application and supported platforms. - -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 browsers, context priority is Firefox > Chrome > Chromium. +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. ## Fields Field | Type | Description | Default :-- | :-- | :-- | :-- -app | object | Required. The application to run. | -app.name | string | Required. Name of the application.

Accepted values: `chrome`, `firefox`, `safari`, `edge` | -app.path | string | Optional. Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped. | -app.options | object | Optional. Options to pass to the app. Only works when `name` is `firefox` or `chrome`. | -app.options.width | integer | Optional. Width of the window in pixels. | -app.options.height | integer | Optional. Height of the window in pixels. | -app.options.viewport_height | integer | Optional. Height of the viewport in pixels. Overrides `height`. | -app.options.viewport_width | integer | Optional. Width of the viewport in pixels. Overrides `width`. | -app.options.headless | boolean | Optional. If `true`, runs the browser in headless mode. Not supported by Safari. | -app.options.driverPath | string | Optional. Path to the browser driver. If not specified, defaults to internally managed dependencies. | -platforms | array of strings | Required. Supported platforms for the application. | +contextId | string | Optional. Unique identifier for the context. | Generated UUID +platforms | One of
- string
- array of string | Optional. Platforms to run tests on. | +browsers | One of
- string
- object
- array of
  one of:
  - string
  - object | Optional. Browsers to run tests on. | +browsers.name | string | Required. Name of the browser.

Accepted values: `chrome`, `firefox`, `safari`, `webkit` | +browsers.headless | boolean | Optional. If `true`, runs the browser in headless mode. | `true` +browsers.window | object | Optional. Browser dimensions. | +browsers.window.width | integer | Optional. Width of the browser window in pixels. | +browsers.window.height | integer | Optional. Height of the browser window in pixels. | +browsers.viewport | object | Optional. Viewport dimensions. | +browsers.viewport.width | integer | Optional. Width of the viewport in pixels. | +browsers.viewport.height | integer | Optional. Height of the viewport in pixels. | ## Examples ```json { - "app": { - "name": "chrome" - }, + "platforms": "linux", + "browsers": "chrome" +} +``` + +```json +{ "platforms": [ + "windows", + "mac", "linux" + ], + "browsers": [ + "chrome", + "firefox", + "webkit" ] } ``` ```json { - "app": { + "browsers": { "name": "chrome", - "options": { - "viewport_width": 800, - "viewport_height": 600 - } - }, - "platforms": [ - "linux" - ] + "headless": true + } } ``` ```json { - "app": { - "name": "firefox", - "options": { - "width": 800, - "height": 600, - "headless": false, - "driverPath": "/usr/bin/geckodriver" + "browsers": [ + { + "name": "chrome", + "headless": true + }, + { + "name": "firefox" } - }, - "platforms": [ - "linux", - "windows", - "mac" ] } ``` ```json { - "app": { - "name": "safari" - }, "platforms": [ - "mac" - ] + "mac", + "linux" + ], + "browsers": { + "name": "chrome", + "headless": true + } } ``` ```json { - "app": { - "name": "firefox", - "path": "/usr/bin/firefox" - }, "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 + } + } + ] +} +``` + +```json +{ + "platforms": "mac", + "browsers": [ + { + "name": "safari", + "window": { + "width": 1280, + "height": 800 + } + } ] } ``` diff --git a/docs/references/schemas/find.md b/docs/references/schemas/find.md index fe739b86..e688be55 100644 --- a/docs/references/schemas/find.md +++ b/docs/references/schemas/find.md @@ -1,49 +1,44 @@ # find -Check if an element exists with the specified CSS selector. +Find an element based on display text or a selector, then optionally interact with it. ## Fields Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. Action to perform. | -selector | string | Required. Selector that uniquely identifies the element. | +elementText | string | Optional. Display text of the element to find. If combined with `selector`, the element must match both the text and the selector. | +selector | string | Optional. Selector of the element to find. If combined with `elementText`, the element must match both the text and the selector. | timeout | integer | Optional. Max duration in milliseconds to wait for the element to exist. | `5000` -matchText | string | Optional. Text that the element should contain. If the element doesn't contain the text, the step fails. Accepts both strings an regular expressions. To use a regular expression, the expression should start and end with a `/`. For example, `/search/`. | -moveTo | [object Object] | Optional. Move to the element. If the element isn't visible, it's scrolled into view. Only runs the if the test is being recorded. | `false` -click | One of
- boolean
- object | Optional. Click the element. | -typeKeys | One of
- string
- object | Optional. Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`typeKeys`](typeKeys). To type in the element, make the element active with the `click` parameter. | -setVariables | array of objects | Optional. Extract environment variables from the element's text. | ``[]`` -setVariables.name | string | Required. Name of the environment variable to set. | -setVariables.regex | string | Required. Regex to extract the environment variable from the element's text. | +moveTo | boolean | Optional. Move to the element. If the element isn't visible, it's scrolled into view. | `true` +click | One of
- object([click](/docs/references/schemas/click))
- object | Optional. Click the element. | +type | undefined | Optional. 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. | ## Examples +```json +"Find me!" +``` + ```json { - "action": "find", "selector": "[title=Search]" } ``` ```json { - "action": "find", "selector": "[title=Search]", "timeout": 10000, - "matchText": "Search", + "elementText": "Search", "moveTo": true, "click": true, - "typeKeys": "shorthair cat" + "type": "shorthair cat" } ``` ```json { - "action": "find", "selector": "[title=Search]", "click": { "button": "right" @@ -53,30 +48,16 @@ setVariables.regex | string | Required. Regex to extract the environment variab ```json { - "action": "find", "selector": "[title=Search]", "timeout": 10000, - "matchText": "Search", + "elementText": "Search", "moveTo": true, "click": true, - "typeKeys": { + "type": { "keys": [ "shorthair cat" ], - "delay": 100 + "inputDelay": 100 } } ``` - -```json -{ - "action": "find", - "selector": "[title=ResultsCount]", - "setVariables": [ - { - "name": "resultsCount", - "regex": ".*" - } - ] -} -``` diff --git a/docs/references/schemas/goTo.md b/docs/references/schemas/goTo.md index dfcc2a91..9d8d8dd9 100644 --- a/docs/references/schemas/goTo.md +++ b/docs/references/schemas/goTo.md @@ -1,42 +1,34 @@ # goTo -Navigate to a specified URL. + ## Fields Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. Action to perform. | -url | string | Required. URL to navigate to. | +url | string | Optional. 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. | origin | string | Optional. Protocol and domain to navigate to. Prepended to `url`. | ## Examples ```json -{ - "action": "goTo", - "url": "https://www.google.com" -} +"https://www.google.com" +``` + +```json +"/search" ``` ```json { - "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", - "description": "This is a test!", - "action": "goTo", "url": "https://www.google.com" } ``` ```json { - "id": "ddec5e20-2e81-4f38-867c-92c8d9516756", - "description": "This is a test!", - "action": "goTo", "url": "/search", - "origin": "https://www.google.com" + "origin": "www.google.com" } ``` diff --git a/docs/references/schemas/httpRequest.md b/docs/references/schemas/httpRequest.md index a60a4c90..4f30ced4 100644 --- a/docs/references/schemas/httpRequest.md +++ b/docs/references/schemas/httpRequest.md @@ -7,63 +7,65 @@ Perform a generic HTTP request, for example to an API. Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. Aciton to perform. | url | string | Optional. URL for the HTTP request. | -openApi | undefined | Optional. undefined | -statusCodes | array of integers | Optional. Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. | ``[200]`` +openApi | unknown | Optional. No description provided. | +statusCodes | array of integer | Optional. Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails. | ``[200,201]`` method | string | Optional. Method of the HTTP request

Accepted values: `get`, `put`, `post`, `patch`, `delete` | `get` timeout | integer | Optional. Timeout for the HTTP request, in milliseconds. | `60000` -requestHeaders | object | Optional. Headers to include in the HTTP request, in key/value format. | ``{}`` -responseHeaders | object | Optional. Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails. | ``{}`` -requestParams | object | Optional. URL parameters to include in the HTTP request, in key/value format. | ``{}`` -responseParams | object | Optional. DEPRECATED. | ``{}`` -requestData | object | Optional. JSON object to include as the body of the HTTP request. | ``{}`` -responseData | object | Optional. JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails. | ``{}`` -allowAdditionalFields | boolean | Optional. If `false`, the step fails when the response data contains fields not specified in `responseData`. | `true` -savePath | string | Optional. File path to save the command's output, relative to `saveDirectory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings. | -saveDirectory | string | Optional. Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. | -maxVariation | integer | Optional. Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored. | `0` -overwrite | string | Optional. If `true`, overwrites the existing output at `savePath` if it exists. -If `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.

Accepted values: `true`, `false`, `byVariation` | `false` -envsFromResponseData | array of objects | Optional. Environment variables to set based on response variables, as an object of the environment variable name and the jq filter applied to the response data to identify the variable's value. | ``[]`` -envsFromResponseData.name | string | Required. Name of the environment variable to set. | -envsFromResponseData.jqFilter | string | Required. jq filter to apply to the response data. If the filter doesn't return a value, the environment variable isn't set. | +request | object | Optional. No description provided. | +request.headers | object | Optional. Headers to include in the HTTP request, in key/value format. | ``{}`` +request.parameters | object | Optional. URL parameters to include in the HTTP request, in key/value format. | ``{}`` +request.body | One of
- object
- array of unknown
- string | Optional. JSON object to include as the body of the HTTP request. | ``{}`` +response | object | Optional. No description provided. | +response.headers | object | Optional. Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails. | ``{}`` +response.body | One of
- object
- array of unknown
- string | Optional. JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails. | ``{}`` +allowAdditionalFields | boolean | Optional. If `false`, the step fails when the response data contains fields not specified in the response body. | `true` +path | string | Optional. 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 | string | Optional. Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. | +maxVariation | number | Optional. Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. | `0` +overwrite | string | Optional. If `true`, overwrites the existing output at `path` if it exists. +If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.

Accepted values: `true`, `false`, `aboveVariation` | `aboveVariation` ## Examples +```json +"https://reqres.in/api/users" +``` + ```json { - "action": "httpRequest", "url": "https://reqres.in/api/users" } ``` ```json { - "action": "httpRequest", "url": "https://reqres.in/api/users/2", "method": "put", - "requestData": { - "name": "morpheus", - "job": "zion resident" + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } } } ``` ```json { - "action": "httpRequest", "url": "https://reqres.in/api/users", "method": "post", - "requestData": { - "name": "morpheus", - "job": "leader" + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } }, - "responseData": { - "name": "morpheus", - "job": "leader" + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } }, "statusCodes": [ 200, @@ -74,24 +76,27 @@ envsFromResponseData.jqFilter | string | Required. jq filter to apply to the re ```json { - "action": "httpRequest", "url": "https://www.api-server.com", "method": "post", "timeout": 30000, - "requestHeaders": { - "header": "value" - }, - "requestParams": { - "param": "value" - }, - "requestData": { - "field": "value" - }, - "responseHeaders": { - "header": "value" + "request": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + }, + "parameters": { + "param": "value" + } }, - "responseData": { - "field": "value" + "response": { + "body": { + "field": "value" + }, + "headers": { + "header": "value" + } }, "statusCodes": [ 200 @@ -101,57 +106,67 @@ envsFromResponseData.jqFilter | string | Required. jq filter to apply to the re ```json { - "action": "httpRequest", "url": "https://reqres.in/api/users", "method": "post", - "requestData": { - "name": "morpheus", - "job": "leader" + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } }, - "responseData": { - "name": "morpheus", - "job": "leader" + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } }, "statusCodes": [ 200, 201 ], - "savePath": "response.json", - "saveDirectory": "media", - "maxVariation": 5, - "overwrite": "byVariation" + "path": "response.json", + "directory": "media", + "maxVariation": 0.05, + "overwrite": "aboveVariation" +} +``` + +```json +{ + "openApi": "getUserById" } ``` ```json { - "action": "httpRequest", "openApi": { "name": "Reqres", "operationId": "getUserById" }, - "requestParams": { - "id": 123 + "request": { + "parameters": { + "id": 123 + } } } ``` ```json { - "action": "httpRequest", "openApi": { "descriptionPath": "https://api.example.com/openapi.json", "operationId": "getUserById" }, - "requestParams": { - "id": 123 + "request": { + "parameters": { + "id": 123 + } } } ``` ```json { - "action": "httpRequest", "openApi": { "descriptionPath": "https://api.example.com/openapi.json", "operationId": "createUser", @@ -162,7 +177,6 @@ envsFromResponseData.jqFilter | string | Required. jq filter to apply to the re ```json { - "action": "httpRequest", "openApi": { "descriptionPath": "https://api.example.com/openapi.json", "operationId": "updateUser", @@ -174,13 +188,12 @@ envsFromResponseData.jqFilter | string | Required. jq filter to apply to the re ```json { - "action": "httpRequest", "openApi": { "descriptionPath": "https://api.example.com/openapi.json", "operationId": "updateUser", "useExample": "request", "exampleKey": "acme", - "requestHeaders": { + "headers": { "Authorization": "Bearer $TOKEN" } } diff --git a/docs/references/schemas/loadVariables.md b/docs/references/schemas/loadVariables.md new file mode 100644 index 00000000..3d18c833 --- /dev/null +++ b/docs/references/schemas/loadVariables.md @@ -0,0 +1,15 @@ + +# loadVariables + +Load environment variables from the specified `.env` file. + +## Fields + +Field | Type | Description | Default +:-- | :-- | :-- | :-- + +## Examples + +```json +".env" +``` diff --git a/docs/references/schemas/record.md b/docs/references/schemas/record.md new file mode 100644 index 00000000..e3d6a0d2 --- /dev/null +++ b/docs/references/schemas/record.md @@ -0,0 +1,30 @@ + +# record + +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' ] + +## Fields + +Field | Type | Description | Default +:-- | :-- | :-- | :-- +path | string | Optional. 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`. | +directory | string | Optional. Directory of the file. If the directory doesn't exist, creates the directory. | +overwrite | string | Optional. If `true`, overwrites the existing recording at `path` if it exists.

Accepted values: `true`, `false` | + +## Examples + +```json +true +``` + +```json +"results.mp4" +``` + +```json +{ + "path": "results.mp4", + "directory": "static/media", + "overwrite": "true" +} +``` diff --git a/docs/references/schemas/runCode.md b/docs/references/schemas/runCode.md index 55c7fe23..19703274 100644 --- a/docs/references/schemas/runCode.md +++ b/docs/references/schemas/runCode.md @@ -7,34 +7,23 @@ Assemble and run code. Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. The action to perform. | -language | string | Required. Language of the code to run. If not specified, the code is run in the shell.

Accepted values: `python`, `bash`, `javascript` | -code | string | Required. Code to run. | -args | array of strings | Optional. Arguments for the command. | ``[]`` +language | string | Optional. Language of the code to run.

Accepted values: `python`, `bash`, `javascript` | +code | string | Optional. Code to run. | +args | array of string | Optional. Arguments for the command. | ``[]`` workingDirectory | string | Optional. Working directory for the command. | `.` -exitCodes | array of integers | Optional. Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. | ``[0]`` -output | string | Optional. Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`. | -savePath | string | Optional. File path to save the command's output, relative to `saveDirectory`. | -saveDirectory | string | Optional. Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. | -maxVariation | integer | Optional. Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored. | `0` -overwrite | string | Optional. If `true`, overwrites the existing output at `savePath` if it exists. -If `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.

Accepted values: `true`, `false`, `byVariation` | `false` +exitCodes | array of integer | Optional. Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. | ``[0]`` +stdio | string | Optional. 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 | string | Optional. File path to save the command's output, relative to `directory`. | +directory | string | Optional. Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. | +maxVariation | number | Optional. Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. | `0` +overwrite | string | Optional. If `true`, overwrites the existing output at `path` if it exists. +If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.

Accepted values: `true`, `false`, `aboveVariation` | `aboveVariation` timeout | integer | Optional. Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. | `60000` -setVariables | array of objects | Optional. Extract environment variables from the command's output. | ``[]`` -setVariables.name | string | Required. Name of the environment variable to set. | -setVariables.regex | string | Required. Regex to extract the environment variable from the command's output. | -outputs | object | Optional. Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. | -outputs.stdout | string | Optional. Standard output of the command. | -outputs.stderr | string | Optional. Standard error of the command. | -outputs.exitCode | integer | Optional. Exit code of the command. | ## Examples ```json { - "action": "runCode", "language": "javascript", "code": "console.log('Hello, ${process.env.USER}!');" } @@ -42,20 +31,18 @@ outputs.exitCode | integer | Optional. Exit code of the command. | ```json { - "action": "runCode", "language": "bash", "code": "docker run hello-world", "timeout": 20000, "exitCodes": [ 0 ], - "output": "Hello from Docker!" + "stdio": "Hello from Docker!" } ``` ```json { - "action": "runCode", "language": "javascript", "code": "return false", "exitCodes": [ @@ -66,17 +53,16 @@ outputs.exitCode | integer | Optional. Exit code of the command. | ```json { - "action": "runCode", "language": "python", "code": "print('Hello from Python')", "workingDirectory": ".", "exitCodes": [ 0 ], - "output": "Hello from Python!", - "savePath": "python-output.txt", - "saveDirectory": "output", - "maxVariation": 10, - "overwrite": "byVariation" + "stdio": "Hello from Python!", + "path": "python-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" } ``` diff --git a/docs/references/schemas/runShell.md b/docs/references/schemas/runShell.md index a99d9211..7fe51191 100644 --- a/docs/references/schemas/runShell.md +++ b/docs/references/schemas/runShell.md @@ -7,29 +7,26 @@ Perform a native shell command. Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. The action to perform. | -command | string | Required. Command to perform in the machine's default shell. | -args | array of strings | Optional. Arguments for the command. | ``[]`` +command | string | Optional. Command to perform in the machine's default shell. | +args | array of string | Optional. Arguments for the command. | ``[]`` workingDirectory | string | Optional. Working directory for the command. | `.` -exitCodes | array of integers | Optional. Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. | ``[0]`` -output | string | Optional. Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`. | -savePath | string | Optional. File path to save the command's output, relative to `saveDirectory`. | -saveDirectory | string | Optional. Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. | -maxVariation | integer | Optional. Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored. | `0` -overwrite | string | Optional. If `true`, overwrites the existing output at `savePath` if it exists. -If `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.

Accepted values: `true`, `false`, `byVariation` | `false` +exitCodes | array of integer | Optional. Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. | ``[0]`` +stdio | string | Optional. 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 | string | Optional. File path to save the command's output, relative to `directory`. | +directory | string | Optional. Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. | +maxVariation | number | Optional. Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. | `0` +overwrite | string | Optional. If `true`, overwrites the existing output at `path` if it exists. +If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.

Accepted values: `true`, `false`, `aboveVariation` | `aboveVariation` timeout | integer | Optional. Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. | `60000` -setVariables | array of objects | Optional. Extract environment variables from the command's output. | ``[]`` -setVariables.name | string | Required. Name of the environment variable to set. | -setVariables.regex | string | Required. Regex to extract the environment variable from the command's output. | ## Examples +```json +"docker run hello-world" +``` + ```json { - "action": "runShell", "command": "echo", "args": [ "$USER" @@ -39,31 +36,26 @@ setVariables.regex | string | Required. Regex to extract the environment variab ```json { - "action": "runShell", "command": "echo", "args": [ "hello-world" - ], - "id": "ddec5e20-2e81-4f38-867c-92c8d9516755", - "description": "This is a test!" + ] } ``` ```json { - "action": "runShell", "command": "docker run hello-world", "timeout": 20000, "exitCodes": [ 0 ], - "output": "Hello from Docker!" + "stdio": "Hello from Docker!" } ``` ```json { - "action": "runShell", "command": "false", "exitCodes": [ 1 @@ -73,7 +65,6 @@ setVariables.regex | string | Required. Regex to extract the environment variab ```json { - "action": "runShell", "command": "echo", "args": [ "setup" @@ -81,28 +72,21 @@ setVariables.regex | string | Required. Regex to extract the environment variab "exitCodes": [ 0 ], - "output": "/.*?/", - "setVariables": [ - { - "name": "TEST", - "regex": ".*" - } - ] + "stdio": "/.*?/" } ``` ```json { - "action": "runShell", "command": "docker run hello-world", "workingDirectory": ".", "exitCodes": [ 0 ], - "output": "Hello from Docker!", - "savePath": "docker-output.txt", - "saveDirectory": "output", - "maxVariation": 10, - "overwrite": "byVariation" + "stdio": "Hello from Docker!", + "path": "docker-output.txt", + "directory": "output", + "maxVariation": 0.1, + "overwrite": "aboveVariation" } ``` diff --git a/docs/references/schemas/saveScreenshot.md b/docs/references/schemas/saveScreenshot.md deleted file mode 100644 index b97d66f2..00000000 --- a/docs/references/schemas/saveScreenshot.md +++ /dev/null @@ -1,93 +0,0 @@ - -# saveScreenshot - -Takes a screenshot in PNG format. - -## Fields - -Field | Type | Description | Default -:-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. The action to perform. | -path | string | Optional. File path of the PNG file, relative to `directory`. If not specified, the file name is the ID of the step. | -directory | string | Optional. Directory of the PNG file. If the directory doesn't exist, creates the directory. | -maxVariation | number | Optional. Allowed variation in percentage of pixels between the new screenshot and the exisitng screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored. | `5` -overwrite | string | Optional. If `true`, overwrites the existing screenshot at `path` if it exists. -If `byVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.

Accepted values: `true`, `false`, `byVariation` | `false` -crop | object | Optional. Crops the screenshot. | -crop.selector | string | Required. Selector of the element to crop the image to. | -crop.padding | One of
- number
- object | Optional. undefined | - -## Examples - -```json -{ - "action": "saveScreenshot" -} -``` - -```json -{ - "action": "saveScreenshot", - "path": "results.png" -} -``` - -```json -{ - "action": "saveScreenshot", - "path": "results.png", - "directory": "static/images" -} -``` - -```json -{ - "action": "saveScreenshot", - "path": "results.png", - "directory": "static/images", - "maxVariation": 10, - "overwrite": "byVariation" -} -``` - -```json -{ - "action": "saveScreenshot", - "path": "results.png", - "directory": "static/images", - "crop": { - "selector": "#element" - } -} -``` - -```json -{ - "action": "saveScreenshot", - "path": "results.png", - "directory": "static/images", - "crop": { - "selector": "#element", - "padding": 10 - } -} -``` - -```json -{ - "action": "saveScreenshot", - "path": "results.png", - "directory": "static/images", - "crop": { - "selector": "#element", - "padding": { - "top": 10, - "right": 20, - "bottom": 30, - "left": 40 - } - } -} -``` diff --git a/docs/references/schemas/screenshot.md b/docs/references/schemas/screenshot.md new file mode 100644 index 00000000..fcdae4f3 --- /dev/null +++ b/docs/references/schemas/screenshot.md @@ -0,0 +1,71 @@ + +# screenshot + +Takes a screenshot in PNG format. + +## Fields + +Field | Type | Description | Default +:-- | :-- | :-- | :-- +path | string | Optional. File path of the PNG file. Accepts absolute paths. If not specified, the file name is the ID of the step. | +directory | string | Optional. Directory of the PNG file. If the directory doesn't exist, creates the directory. | +maxVariation | number | Optional. 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. | `0.05` +overwrite | string | Optional. If `true`, overwrites the existing screenshot at `path` if it exists. +If `aboveVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.

Accepted values: `true`, `false`, `aboveVariation` | `aboveVariation` +crop | One of
- string([Crop by element](/docs/references/schemas/Crop by element))
- object([Crop by element (detailed)](/docs/references/schemas/Crop by element (detailed))) | Optional. No description provided. | + +## Examples + +```json +true +``` + +```json +"image.png" +``` + +```json +"static/images/image.png" +``` + +```json +"/User/manny/projects/doc-detective/static/images/image.png" +``` + +```json +{ + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" +} +``` + +```json +{ + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" +} +``` + +```json +{ + "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 + } + } +} +``` diff --git a/docs/references/schemas/setVariables.md b/docs/references/schemas/setVariables.md deleted file mode 100644 index 1397720c..00000000 --- a/docs/references/schemas/setVariables.md +++ /dev/null @@ -1,22 +0,0 @@ - -# setVariables - -Load environment variables from a `.env` file. - -## Fields - -Field | Type | Description | Default -:-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. Action to perform. | -path | string | Required. Path to the `.env` file. | - -## Examples - -```json -{ - "action": "setVariables", - "path": ".env" -} -``` diff --git a/docs/references/schemas/specification.md b/docs/references/schemas/specification.md index 5bd419be..7afd8d5e 100644 --- a/docs/references/schemas/specification.md +++ b/docs/references/schemas/specification.md @@ -7,11 +7,11 @@ Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. Unique identifier for the test specification. | +specId | string | Optional. Unique identifier for the test specification. | Generated UUID description | string | Optional. Description of the test specification. | -file | string | Optional. Path to the file that the specification is associated with. | -contexts | array of object([context](/docs/references/schemas/context)) | Optional. Application/platform sets to run tests in. Overrides `contexts` defined at the config-level. | -openApi | array of undefineds | Optional. undefined | +contentPath | string | Optional. Path to the content that the specification is associated with. | +runOn | array of object([context](/docs/references/schemas/context)) | Optional. Contexts to run the test in. Overrides contexts defined at the config and spec levels. | +openApi | array of unknown | Optional. No description provided. | tests | array of object([test](/docs/references/schemas/test)) | Required. [Tests](test) to perform. | ## Examples @@ -22,8 +22,9 @@ tests | array of object([test](/docs/references/schemas/test)) | Required. [Tes { "steps": [ { - "action": "checkLink", - "url": "https://www.duckduckgo.com" + "checkLink": { + "url": "https://www.duckduckgo.com" + } } ] } @@ -33,94 +34,110 @@ tests | array of object([test](/docs/references/schemas/test)) | Required. [Tes ```json { - "id": "Do all the things! - Spec", - "contexts": [ + "specId": "Do all the things! - Spec", + "runOn": [ { - "app": { - "name": "chrome", - "path": "/usr/bin/firefox" - }, "platforms": [ "windows", "mac" - ] + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } } ], "tests": [ { - "id": "Do all the things! - Test", + "testId": "Do all the things! - Test", "description": "This test includes nearly every property across all actions.", - "contexts": [ + "runOn": [ { - "app": { - "name": "firefox", - "path": "/usr/bin/firefox" - }, - "platforms": [ - "linux" - ] + "platforms": "linux", + "browsers": "firefox" } ], "steps": [ { - "action": "setVariables", - "path": ".env" + "loadVariables": ".env" }, { - "action": "runShell", - "command": "echo", - "args": [ - "$USER" - ] + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} }, { - "action": "checkLink", - "url": "https://www.duckduckgo.com" + "checkLink": { + "url": "https://www.duckduckgo.com" + } }, { - "action": "httpRequest", - "url": "https://reqres.in/api/users", - "method": "post", - "requestData": { - "name": "morpheus", - "job": "leader" - }, - "responseData": { - "name": "morpheus", - "job": "leader" + "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" }, - "statusCodes": [ - 200, - 201 - ] + "variables": {} }, { - "action": "goTo", - "url": "https://www.duckduckgo.com" + "goTo": { + "url": "https://www.duckduckgo.com" + } }, { - "action": "find", - "selector": "[title=Search]", - "timeout": 10000, - "matchText": "Search", - "moveTo": true, - "click": true, - "typeKeys": { + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} + }, + { + "type": { "keys": [ - "shorthair cat" + "$ENTER$" ] } }, { - "action": "typeKeys", - "keys": [ - "$ENTER$" - ] - }, - { - "action": "saveScreenshot" + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } } - ] + ], + "detectSteps": true } ] } @@ -128,25 +145,35 @@ tests | array of object([test](/docs/references/schemas/test)) | Required. [Tes ```json { - "id": "Make a request from an OpenAPI definition", + "specId": "Make a request from an OpenAPI definition", "openApi": [ { - "name": "Acme", "descriptionPath": "https://www.acme.com/openapi.json", - "server": "https://api.acme.com" + "server": "https://api.acme.com", + "name": "Acme" } ], "tests": [ { "steps": [ { - "action": "httpRequest", - "openApi": { - "operationId": "getUserById" + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" }, - "requestParams": { - "id": 123 - } + "variables": {} } ] } diff --git a/docs/references/schemas/startRecording.md b/docs/references/schemas/startRecording.md deleted file mode 100644 index 0080a801..00000000 --- a/docs/references/schemas/startRecording.md +++ /dev/null @@ -1,39 +0,0 @@ - -# startRecording - -Start recording the current browser viewport. Must be followed by a `stopRecording` action. Only runs when the context `app` is `chrome` and `headless` is `false`. Supported extensions: [ '.mp4', '.webm', '.gif' ] - -## Fields - -Field | Type | Description | Default -:-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. The action to perform. | -path | string | Optional. 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`. | -directory | string | Optional. Directory of the file. Attempts to create the directory if it doesn't exist. | -overwrite | boolean | Optional. If `true`, overwrites the existing file at `path` if it exists. | `false` - -## Examples - -```json -{ - "action": "startRecording" -} -``` - -```json -{ - "action": "startRecording", - "path": "results.mp4" -} -``` - -```json -{ - "action": "startRecording", - "path": "results.mp4", - "directory": "static/media", - "overwrite": true -} -``` diff --git a/docs/references/schemas/step.md b/docs/references/schemas/step.md new file mode 100644 index 00000000..00ec1bb4 --- /dev/null +++ b/docs/references/schemas/step.md @@ -0,0 +1,517 @@ + +# step + +A step in a test. + +## Fields + +Field | Type | Description | Default +:-- | :-- | :-- | :-- +stepId | string | Optional. ID of the step. | +description | string | Optional. Description of the step. | +outputs | object | Optional. Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. | ``{}`` +variables | object | Optional. Environment variables to set from user-defined expressions. | ``{}`` +checkLink | One of
- string
- object | Optional. No description provided. | +click | One of
- string
- object
- boolean | Optional. Click or tap an element. | +find | One of
- string([Find element (simple)](/docs/references/schemas/Find element (simple)))
- object([Find element (detailed)](/docs/references/schemas/Find element (detailed))) | Optional. Find an element based on display text or a selector, then optionally interact with it. | +goTo | One of
- string
- object | Optional. No description provided. | +httpRequest | One of
- string([URL](/docs/references/schemas/URL))
- object | Optional. Perform a generic HTTP request, for example to an API. | +runShell | One of
- string
- object | Optional. Perform a native shell command. | +runCode | object | Optional. Assemble and run code. | +runCode.language | string | Optional. Language of the code to run.

Accepted values: `python`, `bash`, `javascript` | +runCode.code | string | Optional. Code to run. | +runCode.args | array of string | Optional. Arguments for the command. | ``[]`` +runCode.workingDirectory | string | Optional. Working directory for the command. | `.` +runCode.exitCodes | array of integer | Optional. Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails. | ``[0]`` +runCode.stdio | string | Optional. 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.*/`. | +runCode.path | string | Optional. File path to save the command's output, relative to `directory`. | +runCode.directory | string | Optional. Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory. | +runCode.maxVariation | number | Optional. Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `path`, this value is ignored. | `0` +runCode.overwrite | string | Optional. If `true`, overwrites the existing output at `path` if it exists. +If `aboveVariation`, overwrites the existing output at `path` if the difference between the new output and the existing output is greater than `maxVariation`.

Accepted values: `true`, `false`, `aboveVariation` | `aboveVariation` +runCode.timeout | integer | Optional. Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails. | `60000` +type | object | Optional. 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$`. | +type.keys | One of
- string
- array of string | Optional. Sequence of keys to enter. | +type.inputDelay | number | Optional. Delay in milliseconds between each key press during a recording | `100` +type.selector | string | Optional. Selector for the element to type into. If not specified, the typing occurs in the active element. | +screenshot | One of
- string
- object
- boolean | Optional. Takes a screenshot in PNG format. | +record | One of
- string
- object
- boolean | Optional. 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' ] | +stopRecord | boolean | Optional. Stop the current recording. | +loadVariables | string | Optional. Load environment variables from the specified `.env` file. | +wait | One of
- number
- string
- boolean | Optional. Pause (in milliseconds) before performing the next action. | `5000` + +## Examples + +```json +{ + "stepId": "uuid", + "description": "Description of the step.", + "checkLink": "https://www.google.com", + "outputs": { + "outputKey": "outputValue" + }, + "variables": { + "variableKey": "variableValue" + } +} +``` + +```json +{ + "checkLink": "https://www.google.com" +} +``` + +```json +{ + "stepId": "path-only", + "checkLink": "/search" +} +``` + +```json +{ + "stepId": "status-code", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [ + 200 + ] + } +} +``` + +```json +{ + "goTo": { + "url": "https://www.google.com" + } +} +``` + +```json +{ + "goTo": "https://www.google.com" +} +``` + +```json +{ + "wait": 5000 +} +``` + +```json +{ + "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" + } +} +``` + +```json +{ + "stopRecord": true +} +``` + +```json +{ + "screenshot": true +} +``` + +```json +{ + "screenshot": "image.png" +} +``` + +```json +{ + "screenshot": "static/images/image.png" +} +``` + +```json +{ + "screenshot": "/User/manny/projects/doc-detective/static/images/image.png" +} +``` + +```json +{ + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation", + "crop": "#elementToScreenshot" + } +} +``` + +```json +{ + "screenshot": { + "path": "image.png", + "directory": "static/images", + "maxVariation": 0.1, + "overwrite": "aboveVariation" + } +} +``` + +```json +{ + "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 + } + } + } +} +``` + +```json +{ + "record": true +} +``` + +```json +{ + "record": "video.mp4" +} +``` + +```json +{ + "record": "static/media/video.mp4" +} +``` + +```json +{ + "record": "/User/manny/projects/doc-detective/static/media/video.mp4" +} +``` + +```json +{ + "record": { + "path": "video.mp4", + "directory": "static/media", + "overwrite": true + } +} +``` + +```json +{ + "loadVariables": "variables.env" +} +``` + +```json +{ + "find": "Find me!" +} +``` + +```json +{ + "find": { + "selector": "[title=Search]" + } +} +``` + +```json +{ + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": "shorthair cat" + } +} +``` + +```json +{ + "find": { + "selector": "[title=Search]", + "click": { + "button": "right" + } + } +} +``` + +```json +{ + "find": { + "selector": "[title=Search]", + "timeout": 10000, + "elementText": "Search", + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ], + "inputDelay": 100 + } + } +} +``` + +```json +{ + "click": true +} +``` + +```json +{ + "click": "right" +} +``` + +```json +{ + "click": { + "button": "left", + "elementText": "Element text" + } +} +``` + +```json +{ + "click": { + "selector": "#elementToScreenshot", + "elementText": "Element text", + "button": "middle" + } +} +``` + +```json +{ + "httpRequest": "https://reqres.in/api/users" +} +``` + +```json +{ + "httpRequest": { + "url": "https://reqres.in/api/users" + } +} +``` + +```json +{ + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "put", + "request": { + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } +} +``` + +```json +{ + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "post", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "statusCodes": [ + 200, + 201 + ] + } +} +``` + +```json +{ + "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 + ] + } +} +``` + +```json +{ + "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" + } +} +``` + +```json +{ + "httpRequest": { + "openApi": "getUserById" + } +} +``` + +```json +{ + "httpRequest": { + "openApi": { + "name": "Reqres", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } +} +``` + +```json +{ + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 123 + } + } + } +} +``` + +```json +{ + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "createUser", + "useExample": "both" + } + } +} +``` + +```json +{ + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme" + } + } +} +``` + +```json +{ + "httpRequest": { + "openApi": { + "descriptionPath": "https://api.example.com/openapi.json", + "operationId": "updateUser", + "useExample": "request", + "exampleKey": "acme", + "headers": { + "Authorization": "Bearer $TOKEN" + } + } + } +} +``` diff --git a/docs/references/schemas/stopRecord.md b/docs/references/schemas/stopRecord.md new file mode 100644 index 00000000..bb197d39 --- /dev/null +++ b/docs/references/schemas/stopRecord.md @@ -0,0 +1,15 @@ + +# stopRecord + +Stop the current recording. + +## Fields + +Field | Type | Description | Default +:-- | :-- | :-- | :-- + +## Examples + +```json +true +``` diff --git a/docs/references/schemas/stopRecording.md b/docs/references/schemas/stopRecording.md deleted file mode 100644 index f5e8c593..00000000 --- a/docs/references/schemas/stopRecording.md +++ /dev/null @@ -1,20 +0,0 @@ - -# stopRecording - -Stop the current recording. - -## Fields - -Field | Type | Description | Default -:-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. The action to perform. | - -## Examples - -```json -{ - "action": "stopRecording" -} -``` diff --git a/docs/references/schemas/test.md b/docs/references/schemas/test.md index 4c9ccff5..533c9fdf 100644 --- a/docs/references/schemas/test.md +++ b/docs/references/schemas/test.md @@ -7,15 +7,15 @@ A Doc Detective test. Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. Unique identifier for the test. | Generated UUID +testId | string | Optional. Unique identifier for the test. | Generated UUID description | string | Optional. Description of the test. | -file | string | Optional. Path to the file that the test is associated with. | -detectSteps | boolean | Optional. Whether or not to detect steps in input files based on markup regex. Defaults to `true`. | -contexts | array of object([context](/docs/references/schemas/context)) | Optional. Application/platform sets to run the test in. Overrides `contexts` defined at the config-level and spec-level. | -openApi | array of undefineds | Optional. undefined | -setup | string | Optional. Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec. | -cleanup | string | Optional. 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 | array of
- object([checkLink](/docs/references/schemas/checkLink))
- object([goTo](/docs/references/schemas/goTo))
- object([httpRequest](/docs/references/schemas/httpRequest))
- object([runCode](/docs/references/schemas/runCode))
- object([runShell](/docs/references/schemas/runShell))
- object([saveScreenshot](/docs/references/schemas/saveScreenshot))
- object([setVariables](/docs/references/schemas/setVariables))
- object([startRecording](/docs/references/schemas/startRecording))
- object([stopRecording](/docs/references/schemas/stopRecording))
- object([typeKeys](/docs/references/schemas/typeKeys))
- object([find](/docs/references/schemas/find))
- object([wait](/docs/references/schemas/wait)) | Required. Actions to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails. | +contentPath | string | Optional. Path to the content that the test is associated with. | +detectSteps | boolean | Optional. Whether or not to detect steps in input files based on markup regex. | `true` +runOn | array of object([context](/docs/references/schemas/context)) | Optional. Contexts to run the test in. Overrides contexts defined at the config and spec levels. | +openApi | array of unknown | Optional. No description provided. | +before | string | Optional. 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 | string | Optional. 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 | array of
one of:
- unknown
- unknown
- unknown
- unknown
- unknown
- unknown
- unknown
- unknown
- unknown
- unknown
- unknown
- unknown
- unknown | Required. 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. | ## Examples @@ -23,8 +23,7 @@ steps | array of
- object([checkLink](/docs/references/schemas/checkLi { "steps": [ { - "action": "checkLink", - "url": "https://www.duckduckgo.com" + "checkLink": "https://www.duckduckgo.com" } ] } @@ -34,18 +33,20 @@ steps | array of
- object([checkLink](/docs/references/schemas/checkLi { "steps": [ { - "action": "goTo", - "url": "https://www.duckduckgo.com" + "goTo": { + "url": "https://www.duckduckgo.com" + } }, { - "action": "find", - "selector": "[title=Search]", - "click": true, - "typeKeys": { - "keys": [ - "shorthair cats", - "$ENTER$" - ] + "find": { + "selector": "[title=Search]", + "click": true, + "type": { + "keys": [ + "shorthair cats", + "$ENTER$" + ] + } } } ] @@ -54,103 +55,139 @@ steps | array of
- object([checkLink](/docs/references/schemas/checkLi ```json { - "id": "Do all the things! - Test", + "testId": "Do all the things! - Test", "description": "This test includes every property across all actions.", - "contexts": [ + "before": "setup.json", + "after": "cleanup.json", + "runOn": [ { - "app": { - "name": "firefox", - "path": "/usr/bin/firefox" - }, "platforms": [ "linux" - ] + ], + "browsers": { + "name": "firefox", + "window": {}, + "viewport": {} + } } ], - "setup": "setup.json", - "cleanup": "cleanup.json", "steps": [ { - "action": "setVariables", - "path": ".env" + "loadVariables": ".env" }, { - "action": "runShell", - "command": "echo", - "args": [ - "$USER" - ] + "runShell": { + "command": "echo", + "args": [ + "$USER" + ], + "maxVariation": 0, + "overwrite": "aboveVariation" + }, + "variables": {} }, { - "action": "checkLink", - "url": "https://www.duckduckgo.com" + "checkLink": { + "url": "https://www.duckduckgo.com" + } }, { - "action": "httpRequest", - "url": "https://reqres.in/api/users", - "method": "post", - "requestData": { - "name": "morpheus", - "job": "leader" - }, - "responseData": { - "name": "morpheus", - "job": "leader" + "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" }, - "statusCodes": [ - 200, - 201 - ] + "variables": {} + }, + { + "goTo": { + "url": "https://www.duckduckgo.com" + } }, { - "action": "goTo", - "url": "https://www.duckduckgo.com" + "find": { + "selector": "[title=Search]", + "elementText": "Search", + "timeout": 10000, + "moveTo": true, + "click": true, + "type": { + "keys": [ + "shorthair cat" + ] + } + }, + "variables": {} }, { - "action": "find", - "selector": "[title=Search]", - "timeout": 10000, - "matchText": "Search", - "moveTo": true, - "click": true, - "typeKeys": { + "type": { "keys": [ - "shorthair cat" + "$ENTER$" ] } }, { - "action": "typeKeys", - "keys": [ - "$ENTER$" - ] - }, - { - "action": "saveScreenshot" + "screenshot": { + "maxVariation": 0, + "overwrite": "aboveVariation" + } } - ] + ], + "detectSteps": true } ``` ```json { + "testId": "c61b02e8-7485-44d3-8065-f873673379c6", "openApi": [ { - "name": "Acme", "descriptionPath": "https://www.acme.com/openapi.json", - "server": "https://api.acme.com" + "server": "https://api.acme.com", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "", + "name": "Acme" } ], "steps": [ { - "action": "httpRequest", - "openApi": { - "operationId": "getUserById" + "httpRequest": { + "openApi": { + "operationId": "getUserById", + "validateAgainstSchema": "both", + "useExample": "none", + "exampleKey": "" + }, + "request": { + "parameters": { + "id": 123 + } + }, + "response": {}, + "maxVariation": 0, + "overwrite": "aboveVariation" }, - "requestParams": { - "id": 123 - } + "variables": {} } - ] + ], + "detectSteps": true } ``` diff --git a/docs/references/schemas/typeKeys.md b/docs/references/schemas/typeKeys.md index e2242a98..3129d39c 100644 --- a/docs/references/schemas/typeKeys.md +++ b/docs/references/schemas/typeKeys.md @@ -1,30 +1,43 @@ # typeKeys -Type keys. To type special keys, begin and end the string with `$` and use the special key's enum. For example, to type the Escape key, enter `$ESCAPE$`. +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$`. ## Fields Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. The action to perform. | -keys | One of
- string
- array of strings | Required. String of keys to enter. | -delay | number | Optional. Delay in milliseconds between each key press. Only valid during a recording. | `100` +keys | One of
- string
- array of string | Optional. Sequence of keys to enter. | +inputDelay | number | Optional. Delay in milliseconds between each key press during a recording | `100` +selector | string | Optional. Selector for the element to type into. If not specified, the typing occurs in the active element. | ## Examples +```json +"kittens" +``` + +```json +[ + "$ENTER$" +] +``` + +```json +[ + "kittens", + "$ENTER$" +] +``` + ```json { - "action": "typeKeys", "keys": "kittens" } ``` ```json { - "action": "typeKeys", "keys": [ "$ENTER$" ] @@ -33,11 +46,10 @@ delay | number | Optional. Delay in milliseconds between each key press. Only v ```json { - "action": "typeKeys", "keys": [ "kittens", "$ENTER$" ], - "delay": 500 + "inputDelay": 500 } ``` diff --git a/docs/references/schemas/wait.md b/docs/references/schemas/wait.md index dad1556b..37c143ae 100644 --- a/docs/references/schemas/wait.md +++ b/docs/references/schemas/wait.md @@ -1,28 +1,23 @@ # wait -Pause before performing the next action. +Pause (in milliseconds) before performing the next action. ## Fields Field | Type | Description | Default :-- | :-- | :-- | :-- -id | string | Optional. ID of the step. | Generated UUID -description | string | Optional. Description of the step. | -action | string | Required. The action to perform. | -duration | number | Optional. Milliseconds to wait. | `5000` ## Examples ```json -{ - "action": "wait" -} +5000 ``` ```json -{ - "action": "wait", - "duration": 5000 -} +"$WAIT_DURATION" +``` + +```json +true ``` diff --git a/package-lock.json b/package-lock.json index 6e64f47d..2358aa4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doc-detective-docs", - "version": "2.0.6", + "version": "2.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doc-detective-docs", - "version": "2.0.6", + "version": "2.0.7", "dependencies": { "@docusaurus/core": "3.7.0", "@docusaurus/preset-classic": "3.7.0", @@ -17,21 +17,21 @@ "@mui/icons-material": "^6.4.3", "@mui/material": "^6.4.3", "clsx": "^2.1.1", - "doc-detective-common": "^1.22.0", + "doc-detective-common": "^3.0.0", "dotenv": "^16.4.7", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", - "posthog-docusaurus": "^2.0.2", + "posthog-docusaurus": "^2.0.4", "prism-react-renderer": "^2.4.1", "react": "^19.0.0", "react-dom": "^19.0.0", "react-markdown": "^9.0.3", "stream-http": "^3.2.0", - "yaml": "^2.7.0" + "yaml": "^2.7.1" }, "devDependencies": { - "@chromatic-com/storybook": "^3.2.4", + "@chromatic-com/storybook": "^3.2.6", "@docusaurus/module-type-aliases": "3.7.0", "@docusaurus/tsconfig": "3.7.0", "@docusaurus/types": "3.7.0", @@ -304,9 +304,9 @@ } }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.0.tgz", - "integrity": "sha512-8Q/r5mXLa8Rfyh6r4SgEEFJgISVN5cDNFlcfSWLgFn3odzQhTfHAqzI3hMGdcROViL+8NrDNVVFQtEUrYOksDg==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-12.0.1.tgz", + "integrity": "sha512-D3n3T19ly/RYyEvsrqKa/cSAlzQF8KXj1o0XLTI+9GKnJvdHT3WW50yZYCf+4JU7+pLlhXZVV1q1AJ0SPN/pmw==", "license": "MIT", "dependencies": { "@jsdevtools/ono": "^7.1.3", @@ -2002,9 +2002,9 @@ "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==" }, "node_modules/@chromatic-com/storybook": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-3.2.4.tgz", - "integrity": "sha512-5/bOOYxfwZ2BktXeqcCpOVAoR6UCoeART5t9FVy22hoo8F291zOuX4y3SDgm10B1GVU/ZTtJWPT2X9wZFlxYLg==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-3.2.6.tgz", + "integrity": "sha512-FDmn5Ry2DzQdik+eq2sp/kJMMT36Ewe7ONXUXM2Izd97c7r6R/QyGli8eyh/F0iyqVvbLveNYFyF0dBOJNwLqw==", "dev": true, "license": "MIT", "dependencies": { @@ -7514,9 +7514,9 @@ } }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", + "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -10162,34 +10162,19 @@ } }, "node_modules/doc-detective-common": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/doc-detective-common/-/doc-detective-common-1.22.0.tgz", - "integrity": "sha512-l/mp8iow96QhDESJKLwo45IwaP1//5k3EJgJpJuN0E+VC72ZvpFqeaKRqUZXVk3KgDwKPCQdtgvOJ6mhnGP0YA==", - "license": "MIT", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doc-detective-common/-/doc-detective-common-3.0.0.tgz", + "integrity": "sha512-mtRAV/Ysc+JnjqFQZv05eJIQj0MWQtZZQHPdwioXL1PEyl8O0GSSsHsh5iuQk5Nnnf7JYbP3AYzSnYyB93a9xA==", + "license": "AGPL-3.0-only", "dependencies": { - "@apidevtools/json-schema-ref-parser": "^11.9.0", - "ajv": "8.16.0", + "@apidevtools/json-schema-ref-parser": "^12.0.1", + "ajv": "^8.17.1", "ajv-errors": "^3.0.0", "ajv-formats": "^3.0.1", "ajv-keywords": "^5.1.0", - "axios": "^1.7.9", - "uuid": "^11.0.5", - "yaml": "^2.7.0" - } - }, - "node_modules/doc-detective-common/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "axios": "^1.8.4", + "uuid": "^11.1.0", + "yaml": "^2.7.1" } }, "node_modules/doc-detective-common/node_modules/ajv-formats": { @@ -10209,9 +10194,9 @@ } }, "node_modules/doc-detective-common/node_modules/uuid": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz", - "integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -18818,9 +18803,9 @@ } }, "node_modules/posthog-docusaurus": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/posthog-docusaurus/-/posthog-docusaurus-2.0.2.tgz", - "integrity": "sha512-RUxVzJqZ214JuEr1msngxXgTYlK+q37Vhhvp4yG07K+UFF12HBU1TrOdl/MEmvHQimsFQNEa68eYasJo2kAsJA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/posthog-docusaurus/-/posthog-docusaurus-2.0.4.tgz", + "integrity": "sha512-xnEVCBovSuvQvYXGny03CDTc0yZCl7O3Mz21sJpXmE1Gvs21gM33WzWaA9Cm6WvWGYZtQy8t8/g8OjCkmTWlXA==", "license": "MIT", "engines": { "node": ">=10.15.1" @@ -23041,9 +23026,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", + "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index 3bf28f2d..ed73fc75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doc-detective-docs", - "version": "2.0.6", + "version": "2.0.7", "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", @@ -28,21 +28,21 @@ "@mui/icons-material": "^6.4.3", "@mui/material": "^6.4.3", "clsx": "^2.1.1", - "doc-detective-common": "^1.22.0", + "doc-detective-common": "^3.0.0", "dotenv": "^16.4.7", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", - "posthog-docusaurus": "^2.0.2", + "posthog-docusaurus": "^2.0.4", "prism-react-renderer": "^2.4.1", "react": "^19.0.0", "react-dom": "^19.0.0", "react-markdown": "^9.0.3", "stream-http": "^3.2.0", - "yaml": "^2.7.0" + "yaml": "^2.7.1" }, "devDependencies": { - "@chromatic-com/storybook": "^3.2.4", + "@chromatic-com/storybook": "^3.2.6", "@docusaurus/module-type-aliases": "3.7.0", "@docusaurus/tsconfig": "3.7.0", "@docusaurus/types": "3.7.0", From 0d51cd68dd9b2407c8a72339e8bf98fabd9d62ec Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 13:57:25 -0700 Subject: [PATCH 02/31] Update checkLink documentation for clarity and consistency - Clarify usage of `url`, `origin`, and `statusCodes` in the action description. - Standardize examples to use `checkLink` as an object. - Update deprecated `setVariables` action to `loadVariables`. --- docs/get-started/actions/checkLink.md | 107 ++++++++++++++++++++------ 1 file changed, 85 insertions(+), 22 deletions(-) diff --git a/docs/get-started/actions/checkLink.md b/docs/get-started/actions/checkLink.md index 9d70323d..51c7c25c 100644 --- a/docs/get-started/actions/checkLink.md +++ b/docs/get-started/actions/checkLink.md @@ -11,10 +11,11 @@ description: Check if a URL returns an acceptable status code from a GET request The `checkLink` action checks if a URL returns an acceptable status code from a GET request. This action is useful for verifying that a hyperlink or image URL is valid. -You can also specify +You can specify the target URL directly as a string, or use an object for more options: -- an `origin` to navigate to a URL relative to a specific path. -- `statusCodes` to set acceptable HTTP status codes. +- `url`: (Required in object format) The URL to check. Can be a full URL or a path. If a path is provided, an `origin` must be specified either in the step or in the configuration file. +- `origin`: (Optional) Protocol and domain prepended to `url` when `url` is a path. If omitted and `url` is a path, the global `origin` from the configuration file is used. +- `statusCodes`: (Optional) A single integer or an array of integers representing acceptable HTTP status codes. If omitted, defaults to `[200, 301, 302, 307, 308]`. > For comprehensive options, see the [`checkLink`](/docs/references/schemas/checkLink) reference. @@ -22,7 +23,7 @@ You can also specify Here are a few ways you might use the `checkLink` action: -### Check if a link is valid +### Check if a link is valid (string shorthand) ```json { @@ -31,8 +32,46 @@ Here are a few ways you might use the `checkLink` action: "steps": [ { "description": "Check if Google is up.", - "action": "checkLink", - "url": "https://www.google.com" + "checkLink": "https://www.google.com" + } + ] + } + ] +} +``` + +### Check if a link is valid (object format) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Check if Google is up.", + "checkLink": { + "url": "https://www.google.com" + } + } + ] + } + ] +} +``` + +### Check for a specific status code response + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Check if Google is up, expecting only 200.", + "checkLink": { + "url": "https://www.google.com", + "statusCodes": 200 + } } ] } @@ -49,9 +88,10 @@ Here are a few ways you might use the `checkLink` action: "steps": [ { "description": "Check if Google is up with extra status codes.", - "action": "checkLink", - "url": "https://www.google.com", - "statusCodes": [200, 201, 202] + "checkLink": { + "url": "https://www.google.com", + "statusCodes": [200, 201, 202] + } } ] } @@ -67,10 +107,32 @@ Here are a few ways you might use the `checkLink` action: { "steps": [ { - "description": "Check if Google is up with an origin.", - "action": "checkLink", - "url": "/search", - "origin": "https://www.google.com" + "description": "Check if Google search path is valid using a specific origin.", + "checkLink": { + "url": "/search", + "origin": "https://www.google.com" + } + } + ] + } + ] +} +``` + +### Check a relative link using global origin + +Assuming a global `origin` of `https://www.google.com` is set in the configuration: + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Check if Google search path is valid using global origin.", + "checkLink": { + "url": "/search" + } } ] } @@ -97,9 +159,10 @@ Consider the following test configuration, which checks the validity of `https:/ "steps": [ { "description": "Check site with a self-signed certificate", - "action": "checkLink", - "url": "https://self-signed.badssl.com/", - "statusCodes": [200, 201, 202, 301] + "checkLink": { + "url": "https://self-signed.badssl.com/", + "statusCodes": [200, 201, 202, 301] + } } ] } @@ -134,7 +197,7 @@ To fix this issue, follow these steps: NODE_TLS_REJECT_UNAUTHORIZED=0 ``` -2. Modify your test configuration to include a `setVariables` action: +2. Modify your test configuration to include a `loadVariables` step (Note: `setVariables` is deprecated, use `loadVariables`): ```json title="bad-certificate.json" {5-8} { @@ -142,14 +205,14 @@ To fix this issue, follow these steps: { "steps": [ { - "action": "setVariables", - "path": "ignore-certificate-problems.env" + "loadVariables": "ignore-certificate-problems.env" }, { "description": "Check self-signed.badssl.com", - "action": "checkLink", - "url": "https://self-signed.badssl.com/", - "statusCodes": [200, 201, 202, 301] + "checkLink": { + "url": "https://self-signed.badssl.com/", + "statusCodes": [200, 201, 202, 301] + } } ] } From 01c131df46754ca80bd93b6e30ab9e119aff3f6c Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 14:05:10 -0700 Subject: [PATCH 03/31] Enhance `find` action documentation with detailed options and examples - Clarify the description of the `find` action. - Add detailed properties for the object format, including `click`. - Provide multiple examples demonstrating various use cases for the `find` action. --- docs/get-started/actions/find.md | 133 ++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 1 deletion(-) diff --git a/docs/get-started/actions/find.md b/docs/get-started/actions/find.md index 354b01bb..c641b1df 100644 --- a/docs/get-started/actions/find.md +++ b/docs/get-started/actions/find.md @@ -9,6 +9,137 @@ description: Locate and interact with an element on the page. # find -The `find` action locates an element in the current interface and interacts with it, such as validating its text content, clicking it, or typing into it. +The `find` action locates an element in the current interface based on its display text, a CSS selector, or an XPath selector. After finding the element, you can optionally interact with it, such as clicking it or typing into it. + +You can specify the target element directly using a string (for simple text or selector lookup) or use an object for more detailed options and interactions: + +- **String Shorthand:** Provide the display text or CSS selector directly as the value for the `find` key. +- **Object Format:** Use an object with the following properties: + - `elementText`: (Optional) The display text of the element to find. Must be combined with `selector` if both are used. + - `selector`: (Optional) The CSS selector of the element to find. Must be combined with `elementText` if both are used. *At least one of `elementText` or `selector` is required.* + - `timeout`: (Optional) Maximum duration in milliseconds to wait for the element to exist (default: 5000). + - `moveTo`: (Optional) Move the cursor to the element. If the element isn't visible, it's scrolled into view (default: `true`). + - `click`: (Optional) Click the element after finding it. Can be `true` (for a default left click), `"left"`, `"right"`, `"middle"`, or an object like `{ "button": "right" }`. + - `type`: (Optional) Type keys after finding the element. Requires the element to be made active first (e.g., by using `click: true`). Accepts a string or an object like `{ "keys": "my text", "inputDelay": 100 }`. See [`typeKeys`](/docs/references/schemas/typeKeys) for details. > For comprehensive options, see the [`find`](/docs/references/schemas/find) reference. + +## Examples + +Here are a few ways you might use the `find` action: + +### Find an element by its text (string shorthand) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Find the login button by its text.", + "find": "Login" + } + ] + } + ] +} +``` + +### Find an element by its selector (string shorthand) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Find the username field by its ID.", + "find": "#username" + } + ] + } + ] +} +``` + +### Find an element by selector and click it (object format) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Find the submit button by selector and click it.", + "find": { + "selector": "button[type='submit']", + "click": true + } + } + ] + } + ] +} +``` + +### Find an element by selector, click it, and type into it (object format) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Find the search input by selector, click, and type.", + "find": { + "selector": "#input", + "click": true, + "type": "find action" + } + } + ] + } + ] +} +``` + +### Find an element combining selector and text with a timeout + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Find a specific link within a nav bar, waiting up to 10 seconds.", + "find": { + "selector": "nav > ul > li > a", + "elementText": "Downloads", + "timeout": 10000 + } + } + ] + } + ] +} +``` + +### Find an element and right-click it + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Find an image by selector and right-click it.", + "find": { + "selector": "img.product-image", + "click": "right" + } + } + ] + } + ] +} +``` From 38a3a82dc00a6492009266084f64766b1503d938 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 14:28:22 -0700 Subject: [PATCH 04/31] Update `find` action documentation for clarity and detail - Clarify the description of the `find` action to include CSS/XPath selector. - Specify that the element must match both `elementText` and `selector` when used together. - Update example descriptions to reflect the use of CSS selectors. - Add a new example for finding an element and middle-clicking it. --- docs/get-started/actions/find.md | 33 +++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/docs/get-started/actions/find.md b/docs/get-started/actions/find.md index c641b1df..f6dfa8b8 100644 --- a/docs/get-started/actions/find.md +++ b/docs/get-started/actions/find.md @@ -9,14 +9,17 @@ description: Locate and interact with an element on the page. # find -The `find` action locates an element in the current interface based on its display text, a CSS selector, or an XPath selector. After finding the element, you can optionally interact with it, such as clicking it or typing into it. +The `find` action locates an element in the current interface based on its display text or a CSS/XPath selector. After finding the element, you can optionally interact with it, such as clicking it or typing into it. + +If multiple elements match the specified criteria (`elementText` and/or `selector`), the step operates on the first matched element. Ensure your criteria uniquely identify the target element. You can specify the target element directly using a string (for simple text or selector lookup) or use an object for more detailed options and interactions: -- **String Shorthand:** Provide the display text or CSS selector directly as the value for the `find` key. +- **String Shorthand:** Provide the display text or CSS/XPath selector directly as the value for the `find` key. If elements are found by both text and selector, the element found by matching text is used. + - Example: `"find": "Login"` or `"find": "#username"`. - **Object Format:** Use an object with the following properties: - - `elementText`: (Optional) The display text of the element to find. Must be combined with `selector` if both are used. - - `selector`: (Optional) The CSS selector of the element to find. Must be combined with `elementText` if both are used. *At least one of `elementText` or `selector` is required.* + - `elementText`: (Optional) The display text of the element to find. If combined with `selector`, the element must match both. + - `selector`: (Optional) The CSS or XPath selector of the element to find. If combined with `elementText`, the element must match both. *At least one of `elementText` or `selector` is required.* - `timeout`: (Optional) Maximum duration in milliseconds to wait for the element to exist (default: 5000). - `moveTo`: (Optional) Move the cursor to the element. If the element isn't visible, it's scrolled into view (default: `true`). - `click`: (Optional) Click the element after finding it. Can be `true` (for a default left click), `"left"`, `"right"`, `"middle"`, or an object like `{ "button": "right" }`. @@ -53,7 +56,7 @@ Here are a few ways you might use the `find` action: { "steps": [ { - "description": "Find the username field by its ID.", + "description": "Find the username field by its ID (CSS selector).", "find": "#username" } ] @@ -143,3 +146,23 @@ Here are a few ways you might use the `find` action: ] } ``` + +### Find an element and middle-click it + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Find a button by text and middle-click it.", + "find": { + "elementText": "Open New Tab", + "click": "middle" + } + } + ] + } + ] +} +``` From aed9e0bf74391d310582a1b302cf689323a36445 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 14:29:58 -0700 Subject: [PATCH 05/31] Enhance `goTo` action documentation for clarity and detail - Clarify the description of the `goTo` action. - Add details on specifying the target URL as a string or object. - Include examples for using the `goTo` action with different formats. --- docs/get-started/actions/goTo.md | 65 ++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/docs/get-started/actions/goTo.md b/docs/get-started/actions/goTo.md index 0a38bb47..edcf2294 100644 --- a/docs/get-started/actions/goTo.md +++ b/docs/get-started/actions/goTo.md @@ -9,14 +9,23 @@ description: Navigate to a specified URL. # goTo -The `goTo` action navigates to a URL. This action is useful for starting a test at a specific page. +The `goTo` action navigates the browser to a specified URL. This is typically used to start a test at a specific page or navigate between pages during a test. -You can also specify an `origin` to navigate to a URL relative to a specific path. +You can specify the target URL directly as a string, or use an object for more options: + +- **String Shorthand:** Provide the full URL, a path (starting with `/`), or a variable reference directly as the value for the `goTo` key. If a path is provided, it navigates relative to the current URL or the global `origin` if set in the configuration. +- **Object Format:** Use an object with the following properties: + - `url`: (Required) The URL to navigate to. Can be a full URL, a path, or a variable reference. + - `origin`: (Optional) Protocol and domain prepended to `url` when `url` is a path. Overrides the global `origin` if set. > For comprehensive options, see the [`goTo`](/docs/references/schemas/goTo) reference. ## Examples +Here are a few ways you might use the `goTo` action: + +### Navigate to a full URL (string shorthand) + ```json { "tests": [ @@ -24,8 +33,7 @@ You can also specify an `origin` to navigate to a URL relative to a specific pat "steps": [ { "description": "Navigate to example.com.", - "action": "goTo", - "url": "https://example.com" + "goTo": "https://example.com" } ] } @@ -33,16 +41,57 @@ You can also specify an `origin` to navigate to a URL relative to a specific pat } ``` +### Navigate to a relative path (string shorthand) + +Assumes the browser is currently at `https://example.com` or a global `origin` is set. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Navigate to the /about path.", + "goTo": "/about" + } + ] + } + ] +} +``` + +### Navigate using an object with a full URL + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Navigate to example.com using object format.", + "goTo": { + "url": "https://example.com" + } + } + ] + } + ] +} +``` + +### Navigate using an object with a relative path and specific origin + ```json { "tests": [ { "steps": [ { - "description": "Navigate to with an origin.", - "action": "goTo", - "url": "/search", - "origin": "https://www.google.com" + "description": "Navigate to Google search using a specific origin.", + "goTo": { + "url": "/search", + "origin": "https://www.google.com" + } } ] } From 94334f579ef9a230f9556cd028c6dcdeb6d4f301 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 14:35:26 -0700 Subject: [PATCH 06/31] Enhance `runShell` action documentation for clarity and detail - Clarify usage of the `runShell` action and its command execution context. - Expand options for command specification, including arguments and working directory. - Update examples to reflect new object format for commands. - Improve descriptions for expected output validation and exit code handling. - Revise variable setting instructions for better clarity. --- docs/get-started/actions/runShell.md | 91 ++++++++++++++++++---------- 1 file changed, 59 insertions(+), 32 deletions(-) diff --git a/docs/get-started/actions/runShell.md b/docs/get-started/actions/runShell.md index e5869611..32bf0f9c 100644 --- a/docs/get-started/actions/runShell.md +++ b/docs/get-started/actions/runShell.md @@ -11,22 +11,29 @@ description: Perform a native shell command. The `runShell` action runs a shell command or script on the local machine and evaluates the results, extending Doc Detective's testing capabilities to anything you can script. -> For comprehensive options, see the [`runShell`](/docs/references/schemas/runShell) reference. +`runShell` uses your device's native shell (`cmd` on Windows, `bash` or other default shell on macOS/Linux) to execute the command in the context of the current user. -`runShell` uses your device's native shell (`cmd` on Windows, `bash` on macOS and Linux) to execute the command. The command is executed in the context of the current user. +You can specify the command directly as a string or use an object for more options: -`runShell` can evaluate commands in two ways: +- **String Shorthand:** Provide the command string directly as the value for the `runShell` key. +- **Object Format:** Use an object with the following properties: + - `command`: (Required) The command or script to execute. + - `args`: (Optional) An array of arguments to pass to the command. + - `workingDirectory`: (Optional) The directory in which to run the command. + - `timeout`: (Optional) Maximum duration in milliseconds to wait for the command to complete. + - `exitCodes`: (Optional) An array of acceptable exit codes. If the command's exit code is not in this list, the step fails (default: `[0]`). + - `stdio`: (Optional) A string or regular expression to validate against the command's combined stdout and stderr. If the output doesn't match, the step fails. Regex must start and end with `/` (e.g., `/^hello world.*/`). + - *Output Saving:* You can also save the command's output using `path`, `directory`, `maxVariation`, and `overwrite` properties. See the [`runShell`](/docs/references/schemas/runShell) reference for details. -- **Exit code**: The command's exit code is checked against a list of expected exit codes set in the `exitCodes` parameter. If the command's exit code exists in the list of expected codes, the step passes. `exitCodes` defaults to `[0]`. You can specify non-zero exit codes to test for failure conditions. -- **Output**: If the expected output (as set in the `output` parameter) exists in the command's actual output (both stdout and stderr), the step passes. You can specify expected output as a string or a regular expression. To use a regular expression, the string must start and end with a forward slash, like in `/^hello world.*/`. +**Setting Variables:** To capture output into variables for later steps, use the step-level `variables` object. You can assign values based on the command's output using expressions like `runShell.stdout`, `runShell.stderr`, or `runShell.output` (combined stdio). -You can also set variables based on the command's output with the `setVariables` parameter. This is useful for capturing the output of a command and using it in subsequent steps. Each variable is set based on a regular expression match of the command's output. +> For comprehensive options, see the [`runShell`](/docs/references/schemas/runShell) reference. ## Examples Here are a few ways you might use the `runShell` action: -### Run a simple command +### Run a simple command (string shorthand) This example prints "hello world" to the output. @@ -36,9 +43,28 @@ This example prints "hello world" to the output. { "steps": [ { - "action": "runShell", "description": "Run a simple command.", - "command": "echo 'hello world'" + "runShell": "echo 'hello world'" + } + ] + } + ] +} +``` + +### Run a command with arguments (object format) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Run echo with arguments.", + "runShell": { + "command": "echo", + "args": ["hello", "world"] + } } ] } @@ -46,7 +72,7 @@ This example prints "hello world" to the output. } ``` -### Run a command with expected output +### Run a command with expected output validation This example runs a Docker container and checks the output for a specific string. @@ -56,10 +82,11 @@ This example runs a Docker container and checks the output for a specific string { "steps": [ { - "action": "runShell", "description": "Run a Docker container and check the output.", - "command": "docker run hello-world", - "output": "Hello from Docker!" + "runShell": { + "command": "docker run hello-world", + "stdio": "Hello from Docker!" + } } ] } @@ -67,9 +94,9 @@ This example runs a Docker container and checks the output for a specific string } ``` -### Test a failure condition +### Test a failure condition using exit codes -This example runs a failing command and checks the exit code. Because the command is expected to fail with an exit code `1`, the step passes. +This example runs a failing command (`false`) and checks that the exit code is `1`. Because the command is expected to fail with exit code 1, the step passes. ```json { @@ -77,10 +104,11 @@ This example runs a failing command and checks the exit code. Because the comman { "steps": [ { - "action": "runShell", - "description": "Run a failing command.", - "command": "false", - "exitCodes": [1] + "description": "Run a failing command and expect exit code 1.", + "runShell": { + "command": "false", + "exitCodes": [1] + } } ] } @@ -90,7 +118,7 @@ This example runs a failing command and checks the exit code. Because the comman ### Set a variable based on command output -The first step echoes "setup", validates that it outputs a string or one or more characters, and sets a variable based on the output. The next step echoes the variable, then validates that the command output "setup". +The first step echoes "setup", validates the output using a regex, and captures the full stdout into a variable named `TEST`. The second step echoes the content of the `TEST` variable and validates that the output is indeed "setup". ```json { @@ -98,22 +126,21 @@ The first step echoes "setup", validates that it outputs a string or one or more { "steps": [ { - "action": "runShell", "description": "Set a variable based on command output.", - "command": "echo setup", - "output": "/.+/", - "setVariables": [ - { - "name": "TEST", - "regex": ".*" - } - ] + "runShell": { + "command": "echo setup", + "stdio": "/.+/" + }, + "variables": { + "TEST": "$$stdio.stdout" + } }, { - "action": "runShell", "description": "Echo and validate the variable.", - "command": "echo $TEST", - "output": "setup" + "runShell": { + "command": "echo $TEST", + "stdio": "setup" + } } ] } From 4abf450423cd157cc461a74b7ad155988c906f9f Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 14:46:45 -0700 Subject: [PATCH 07/31] Add documentation for `runCode` action - Introduce `runCode` action to execute code snippets in various languages. - Specify required and optional properties for the action. - Provide examples for using the action with Python, JavaScript, and Bash. --- docs/get-started/actions/runCode.md | 138 ++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 docs/get-started/actions/runCode.md diff --git a/docs/get-started/actions/runCode.md b/docs/get-started/actions/runCode.md new file mode 100644 index 00000000..c830f8d6 --- /dev/null +++ b/docs/get-started/actions/runCode.md @@ -0,0 +1,138 @@ +--- +title: runCode +layout: default +nav_order: 1 # Adjust nav_order as needed +parent: Actions +grand_parent: Tests +description: Assemble and run code snippets in various languages. +--- + +# runCode + +The `runCode` action executes a code snippet in a specified language (like JavaScript, Python, Bash, etc.) on the local machine and evaluates the results. This allows embedding executable code directly within your tests. + +`runCode` executes the code using the appropriate interpreter available on the machine. + +You must specify the `runCode` action using an object format with the following properties: + +- **Object Format:** + - `language`: (Required) The programming language of the code snippet (`javascript`, `python`, `bash`). + + > Note: `bash` isn't currently supported on Windows. + + - `code`: (Required) The code snippet to execute as a string. + - `workingDirectory`: (Optional) The directory in which to run the code. + - `timeout`: (Optional) Maximum duration in milliseconds to wait for the code execution to complete. + - `exitCodes`: (Optional) An array of acceptable exit codes. If the code execution's exit code is not in this list, the step fails (default: `[0]`). + - `stdio`: (Optional) A string or regular expression to validate against the code's combined stdout and stderr. If the output doesn't match, the step fails. Regex must start and end with `/` (e.g., `/^hello world.*/`). + - *Output Saving:* You can also save the code's output using `path`, `directory`, `maxVariation`, and `overwrite` properties. See the [`runCode`](/docs/references/schemas/runCode) reference for details. + +**Setting Variables:** To capture output into variables for later steps, use the step-level `variables` object. You can assign values based on the code's output using expressions like `runCode.stdout`, `runCode.stderr`, or `runCode.output` (combined stdio). + +> For comprehensive options, see the [`runCode`](/docs/references/schemas/runCode) reference. + +## Examples + +Here are a few ways you might use the `runCode` action: + +### Run a simple Python script + +This example prints "hello world" using Python. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Run a simple Python script.", + "runCode": { + "language": "python", + "code": "print('hello world')" + } + } + ] + } + ] +} +``` + +### Run JavaScript code with expected output validation + +This example runs a simple Node.js script and checks the output. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Run JS code and check the output.", + "runCode": { + "language": "javascript", + "code": "console.log('Hello from Node!');", + "stdio": "Hello from Node!" + } + } + ] + } + ] +} +``` + +### Test a failure condition using exit codes (Bash) + +This example runs a Bash command (`false`) via `runCode` and checks that the exit code is `1`. Because the command is expected to fail with exit code 1, the step passes. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Run a failing Bash command and expect exit code 1.", + "runCode": { + "language": "bash", + "code": "false", + "exitCodes": [1] + } + } + ] + } + ] +} +``` + +### Set a variable based on code output (Python) + +The first step runs Python code to print "setup", validates the output using a regex, and captures the full stdout into a variable named `SETUP_VAL`. The second step uses Bash via `runCode` to echo the content of the `SETUP_VAL` variable and validates that the output is indeed "setup". + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Set a variable based on Python output.", + "runCode": { + "language": "python", + "code": "import sys; sys.stdout.write('setup')", + "stdio": "/.+/" + }, + "variables": { + "SETUP_VAL": "$$stdio.stdout" + } + }, + { + "description": "Echo and validate the variable using Bash.", + "runCode": { + "language": "bash", + "code": "echo $SETUP_VAL", + "stdio": "setup" + } + } + ] + } + ] +} +``` From 5474eff4bcd00593acc613f69b4865267a8ad8d5 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 14:56:23 -0700 Subject: [PATCH 08/31] Enhance documentation for `httpRequest` action - Clarify the description and usage of the `httpRequest` action. - Add detailed options for request and response configurations. - Include examples for various request types (GET, POST, PUT) and OpenAPI usage. - Provide instructions for setting variables from response bodies and saving responses to files. --- docs/get-started/actions/httpRequest.md | 267 +++++++++++++++++++++++- 1 file changed, 266 insertions(+), 1 deletion(-) diff --git a/docs/get-started/actions/httpRequest.md b/docs/get-started/actions/httpRequest.md index b432b9b2..64a8a48a 100644 --- a/docs/get-started/actions/httpRequest.md +++ b/docs/get-started/actions/httpRequest.md @@ -9,6 +9,271 @@ description: Perform a generic HTTP request, for example to an API. # httpRequest -The `httpRequest` action makes arbitrary HTTP calls, allowing you to call and validate APIs and use web services. +The `httpRequest` action makes arbitrary HTTP calls, allowing you to interact with and validate APIs or other web services directly within your tests. + +You can specify a simple GET request using a string shorthand or use an object for more complex requests and validation: + +- **String Shorthand:** Provide the full URL directly as the value for the `httpRequest` key. This performs a simple GET request to that URL. +- **Object Format:** Use an object with the following properties: + - `url`: (Required unless using `openApi`) The target URL for the request. + - `method`: (Optional) The HTTP method (e.g., `GET`, `POST`, `PUT`, `DELETE`). Defaults to `GET`. + - `timeout`: (Optional) Maximum duration in milliseconds to wait for the request to complete. + - `request`: (Optional) An object defining the request details: + - `headers`: (Optional) Key-value pairs for request headers. + - `parameters`: (Optional) Key-value pairs for query string parameters. + - `body`: (Optional) The request body. Can be a string or JSON object. + - `response`: (Optional) An object defining expected response validation: + - `headers`: (Optional) Key-value pairs for expected response headers. Values must be strings. + - `body`: (Optional) Expected response body. Can be a string or JSON object. + - `statusCodes`: (Optional) An array of acceptable HTTP status codes. If the response code is not in this list, the step fails (default: `[200]`). + - `openApi`: (Optional) Define the request based on an OpenAPI definition. Can be a string (operation ID) or an object: + - `name`: (Optional) Name of the registered OpenAPI definition (if multiple are loaded). + - `descriptionPath`: (Optional) Path or URL to the OpenAPI description file. + - `operationId`: (Required) The ID of the operation to use. + - `useExample`: (Optional) Use example data from the OpenAPI spec (`request`, `response`, or `both`). + - `exampleKey`: (Optional) Key of the specific example to use if multiple exist. + *Note: Properties like `request.headers`, `request.parameters`, `request.body` can override values from the OpenAPI definition or example.* + - *Output Saving:* You can also save the response body using `path`, `directory`, `maxVariation`, and `overwrite` properties. See the [`httpRequest`](/docs/references/schemas/httpRequest) reference for details. + +**Setting Variables:** To capture parts of the response for later steps, use the step-level `variables` object. You can assign values based on the response using expressions like `$$response.body`, `$$response.headers`, `$$response.status`, etc. You can use dot notation for nested JSON fields (e.g., `$$response.body.user.id`). > For comprehensive options, see the [`httpRequest`](/docs/references/schemas/httpRequest) reference. + +## Examples + +Here are a few ways you might use the `httpRequest` action: + +### Simple GET request (string shorthand) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Perform a simple GET request.", + "httpRequest": "https://reqres.in/api/users?page=2" + } + ] + } + ] +} +``` + +### Simple GET request (object format) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Perform a simple GET request using object format.", + "httpRequest": { + "url": "https://reqres.in/api/users?page=2" + } + } + ] + } + ] +} +``` + +### POST request with JSON body + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Create a user via POST request.", + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "POST", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + } + } + } + ] + } + ] +} +``` + +### PUT request with headers and query parameters + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Update a user via PUT request.", + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "PUT", + "request": { + "headers": { + "Content-Type": "application/json" + }, + "parameters": { + "source": "test" + }, + "body": { + "name": "morpheus", + "job": "zion resident" + } + } + } + } + ] + } + ] +} +``` + +### Validate response status code and body + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Create user and validate response.", + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "POST", + "request": { + "body": { + "name": "morpheus", + "job": "leader" + } + }, + "response": { + "body": { + "name": "morpheus", + "job": "leader", + } + }, + "statusCodes": [201] // Expect HTTP 201 Created + } + } + ] + } + ] +} +``` + +### Use OpenAPI definition (by operation ID) + +Assumes an OpenAPI definition with operation ID `getUserById` is loaded. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Get user by ID using OpenAPI definition.", + "httpRequest": { + "openApi": "getUserById", + "request": { + "parameters": { // Provide required path parameter + "id": 2 + } + } + } + } + ] + } + ] +} +``` + +### Use OpenAPI definition (detailed object) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Get user by ID using specific OpenAPI file.", + "httpRequest": { + "openApi": { + "descriptionPath": "./reqres.openapi.json", + "operationId": "getUserById" + }, + "request": { + "parameters": { + "id": 3 + } + } + } + } + ] + } + ] +} +``` + +### Set a variable from response body + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Create user and capture the ID.", + "httpRequest": { + "url": "https://reqres.in/api/users", + "method": "POST", + "request": { + "body": {"name": "neo", "job": "the one"} + }, + "statusCodes": [201] + }, + "variables": { + "USER_ID": "$$response.body.id" + } + }, + { + "description": "Use the captured ID in the next request.", + "httpRequest": { + "url": "https://reqres.in/api/users/$USER_ID", // Use variable in URL + "method": "GET" + } + } + ] + } + ] +} +``` + +### Save response body to a file + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Get user data and save response to file.", + "httpRequest": { + "url": "https://reqres.in/api/users/2", + "method": "GET", + "path": "user_2_response.json", // File name + "directory": "./output/api_responses" // Output directory + } + } + ] + } + ] +} From f4e06a17ba40fbba0942d9ae7c7cfb14d4aab517 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 14:58:27 -0700 Subject: [PATCH 09/31] Fixed output values --- docs/get-started/actions/runCode.md | 2 +- docs/get-started/actions/runShell.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/get-started/actions/runCode.md b/docs/get-started/actions/runCode.md index c830f8d6..3236c3f3 100644 --- a/docs/get-started/actions/runCode.md +++ b/docs/get-started/actions/runCode.md @@ -27,7 +27,7 @@ You must specify the `runCode` action using an object format with the following - `stdio`: (Optional) A string or regular expression to validate against the code's combined stdout and stderr. If the output doesn't match, the step fails. Regex must start and end with `/` (e.g., `/^hello world.*/`). - *Output Saving:* You can also save the code's output using `path`, `directory`, `maxVariation`, and `overwrite` properties. See the [`runCode`](/docs/references/schemas/runCode) reference for details. -**Setting Variables:** To capture output into variables for later steps, use the step-level `variables` object. You can assign values based on the code's output using expressions like `runCode.stdout`, `runCode.stderr`, or `runCode.output` (combined stdio). +**Setting Variables:** To capture output into variables for later steps, use the step-level `variables` object. You can assign values based on the code's output using expressions like `$$stdio.stdout`, `$$stdio.stderr`, or `$$exitCode`. > For comprehensive options, see the [`runCode`](/docs/references/schemas/runCode) reference. diff --git a/docs/get-started/actions/runShell.md b/docs/get-started/actions/runShell.md index 32bf0f9c..bcecde15 100644 --- a/docs/get-started/actions/runShell.md +++ b/docs/get-started/actions/runShell.md @@ -24,8 +24,8 @@ You can specify the command directly as a string or use an object for more optio - `exitCodes`: (Optional) An array of acceptable exit codes. If the command's exit code is not in this list, the step fails (default: `[0]`). - `stdio`: (Optional) A string or regular expression to validate against the command's combined stdout and stderr. If the output doesn't match, the step fails. Regex must start and end with `/` (e.g., `/^hello world.*/`). - *Output Saving:* You can also save the command's output using `path`, `directory`, `maxVariation`, and `overwrite` properties. See the [`runShell`](/docs/references/schemas/runShell) reference for details. - -**Setting Variables:** To capture output into variables for later steps, use the step-level `variables` object. You can assign values based on the command's output using expressions like `runShell.stdout`, `runShell.stderr`, or `runShell.output` (combined stdio). + +**Setting Variables:** To capture output into variables for later steps, use the step-level `variables` object. You can assign values based on the code's output using expressions like `$$stdio.stdout`, `$$stdio.stderr`, or `$$exitCode`. > For comprehensive options, see the [`runShell`](/docs/references/schemas/runShell) reference. From 28dd29b9dbf32113d9e1ba07391cd1e8005efe47 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 14:59:40 -0700 Subject: [PATCH 10/31] Enhance documentation for `find` action - Add details on setting variables to capture element attributes for later steps. --- docs/get-started/actions/find.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/get-started/actions/find.md b/docs/get-started/actions/find.md index f6dfa8b8..269ec122 100644 --- a/docs/get-started/actions/find.md +++ b/docs/get-started/actions/find.md @@ -25,6 +25,8 @@ You can specify the target element directly using a string (for simple text or s - `click`: (Optional) Click the element after finding it. Can be `true` (for a default left click), `"left"`, `"right"`, `"middle"`, or an object like `{ "button": "right" }`. - `type`: (Optional) Type keys after finding the element. Requires the element to be made active first (e.g., by using `click: true`). Accepts a string or an object like `{ "keys": "my text", "inputDelay": 100 }`. See [`typeKeys`](/docs/references/schemas/typeKeys) for details. +**Setting Variables:** To capture a found element's attributes into variables for later steps, use the step-level `variables` object. You can assign values based on the element using expressions like `$$element.text`. + > For comprehensive options, see the [`find`](/docs/references/schemas/find) reference. ## Examples From f4696da771300a6165f4a1d745d4f66d5c1578ca Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 15:04:51 -0700 Subject: [PATCH 11/31] Add documentation for `screenshot` action - Create a new documentation file for the `screenshot` action. - Describe the functionality, options, and examples for taking screenshots. - Include details on visual regression testing and cropping options. --- docs/get-started/actions/saveScreenshot.md | 14 -- docs/get-started/actions/screenshot.md | 148 +++++++++++++++++++++ 2 files changed, 148 insertions(+), 14 deletions(-) delete mode 100644 docs/get-started/actions/saveScreenshot.md create mode 100644 docs/get-started/actions/screenshot.md diff --git a/docs/get-started/actions/saveScreenshot.md b/docs/get-started/actions/saveScreenshot.md deleted file mode 100644 index 776c97d7..00000000 --- a/docs/get-started/actions/saveScreenshot.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: saveScreenshot -layout: default -nav_order: 1 -parent: Actions -grand_parent: Tests -description: Take a screenshot in PNG format. ---- - -# saveScreenshot - -The `saveScreenshot` action captures a PNG of the current viewport. If an image with the same name and dimensions exists, it can also perform pixel diffs and capture updated screenshots for debugging or media updating purposes. - -> For comprehensive options, see the [`saveScreenshot`](/docs/references/schemas/saveScreenshot) reference. diff --git a/docs/get-started/actions/screenshot.md b/docs/get-started/actions/screenshot.md new file mode 100644 index 00000000..6ffe9ac1 --- /dev/null +++ b/docs/get-started/actions/screenshot.md @@ -0,0 +1,148 @@ +--- +title: screenshot +layout: default +nav_order: 1 # Adjust nav_order as needed +parent: Actions +grand_parent: Tests +description: Take a screenshot in PNG format and optionally perform visual regression testing. +--- + +# screenshot + +The `screenshot` action captures a PNG image of the current browser viewport or a specific element. It can also perform visual regression testing by comparing the captured image against a previously saved reference image. + +You can specify the screenshot action in several ways: + +- **Boolean Shorthand:** Set `screenshot: true` to capture the full viewport with default settings. +- **String Shorthand:** Provide a file path directly as the value for the `screenshot` key (e.g., `screenshot: "my_screenshot.png"`). This saves the full viewport screenshot to the specified path. +- **Object Format:** Use an object for more control over the path, visual comparison, and cropping: + - `path`: (Optional) The file path where the screenshot will be saved. Can include directories. If omitted, a default path is generated. + - `directory`: (Optional) The directory where the screenshot will be saved. If `path` includes a directory, this is ignored. Defaults to the configured output directory. + - `maxVariation`: (Optional) The maximum acceptable visual difference (0 to 1) when comparing against a reference image. If the variation exceeds this threshold, the step fails. If set, visual comparison is enabled. + - `overwrite`: (Optional) Controls when to overwrite the reference image. Options: + - `never`: Never overwrite the reference image (default). + - `always`: Always overwrite the reference image with the new capture. + - `aboveVariation`: Overwrite only if the visual difference exceeds `maxVariation`. + - `crop`: (Optional) Crop the screenshot to a specific element. Provide a CSS/XPath selector string (e.g., `"#myElement"`) or an object: + - `selector`: (Required in object) The CSS or XPath selector of the element to crop to. + - `elementText`: (Optional) Display text to further specify the element if the selector isn't unique. + - `padding`: (Optional) Add padding around the element before cropping. Can be a single number (all sides) or an object `{ top, right, bottom, left }`. + +**Visual Regression Testing:** If `maxVariation` is set and a reference image exists at the target `path`, the action compares the new screenshot to the reference. If the difference is within `maxVariation`, the step passes. If it exceeds the threshold, the step fails, and behavior depends on the `overwrite` setting. + +> For comprehensive options, see the [`screenshot`](/docs/references/schemas/screenshot) reference. + +## Examples + +Here are a few ways you might use the `screenshot` action: + +### Simple full viewport screenshot (boolean shorthand) + +Saves to a default path like `output/screenshot_1745032062266.png`. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Take a simple screenshot.", + "screenshot": true + } + ] + } + ] +} +``` + +### Full viewport screenshot to specific path (string shorthand) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Save screenshot to a specific file.", + "screenshot": "./output/images/login_page.png" + } + ] + } + ] +} +``` + +### Full viewport screenshot with visual comparison (object format) + +Compares against `./output/reference_images/home_page.png`. Fails if difference > 5% (`0.05`). Overwrites reference if failure occurs. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Take screenshot and compare to reference.", + "screenshot": { + "path": "home_page.png", + "directory": "./output/reference_images", + "maxVariation": 0.05, + "overwrite": "aboveVariation" + } + } + ] + } + ] +} +``` + +### Screenshot cropped to an element (object format) + +Captures only the element matching the `#main-content` selector. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Screenshot only the main content area.", + "screenshot": { + "path": "main_content_area.png", + "directory": "./output/element_shots", + "crop": "#main-content" + } + } + ] + } + ] +} +``` + +### Screenshot cropped to an element with padding and visual comparison + +Captures the element with text "Submit Button", adds 10px padding, and compares against a reference image. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Screenshot a button with padding and compare.", + "screenshot": { + "path": "submit_button_padded.png", + "directory": "./output/reference_elements", + "crop": { + "elementText": "Submit Button", + "padding": 10 + }, + "maxVariation": 0.01, + "overwrite": "aboveVariation" + } + } + ] + } + ] +} +``` From 8d7dce020111d48a5b2f956db20e06fd643ad866 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 15:08:42 -0700 Subject: [PATCH 12/31] Add documentation for `loadVariables` action - Create a new documentation file for the `loadVariables` action. - Describe the purpose and usage of loading environment variables from a `.env` file. - Provide an example of how to use the `loadVariables` action in a test. - Remove the outdated `setVariables` documentation file. --- docs/get-started/actions/loadVariables.md | 54 +++++++++++++++++++++++ docs/get-started/actions/setVariables.md | 32 -------------- 2 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 docs/get-started/actions/loadVariables.md delete mode 100644 docs/get-started/actions/setVariables.md diff --git a/docs/get-started/actions/loadVariables.md b/docs/get-started/actions/loadVariables.md new file mode 100644 index 00000000..b3c96339 --- /dev/null +++ b/docs/get-started/actions/loadVariables.md @@ -0,0 +1,54 @@ +--- +title: loadVariables +layout: default +nav_order: 1 +parent: Actions +grand_parent: Tests +description: Load environment variables from a .env file. +--- + +# loadVariables + +The `loadVariables` action loads environment variables from a specified `.env` file. This action is useful for accessing sensitive information, such as API keys or other credentials, without hardcoding them into your tests. Variables loaded this way are available for use in subsequent steps within the same test. + +> You can also load globally applicable variables using the `loadVariables` property in the configuration file. This makes them available across all tests. +> +> For comprehensive options, see the [`loadVariables`](/docs/references/schemas/loadVariables) reference. + +## Example + +Assuming a file named `secrets.env` exists in the same directory as the test file or at the specified path: + +```env title="secrets.env" +API_KEY=your_secret_api_key +BASE_URL=https://api.example.com +``` + +You can load these variables using the `loadVariables` action: + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Load environment variables from secrets.env.", + "loadVariables": "./secrets.env" + }, + { + "description": "Use the loaded API key in an HTTP request.", + "httpRequest": { + "url": "$BASE_URL/data", // Use loaded BASE_URL + "method": "GET", + "request": { + "headers": { + "Authorization": "Bearer $API_KEY" // Use loaded API_KEY + } + } + } + } + ] + } + ] +} +``` diff --git a/docs/get-started/actions/setVariables.md b/docs/get-started/actions/setVariables.md deleted file mode 100644 index dc5904a6..00000000 --- a/docs/get-started/actions/setVariables.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: setVariables -layout: default -nav_order: 1 -parent: Actions -grand_parent: Tests -description: Load environment variables from a .env file. ---- - -# setVariables - -The `setVariables` action sets environment variables from a `.env` file. This action is useful for accessing sensitive information, such as API keys or other credentials, without hardcoding them into your tests. - -> For comprehensive options, see the [`setVariables`](/docs/references/schemas/setVariables) reference. - -## Example - -```json -{ - "tests": [ - { - "steps": [ - { - "description": "Set environment variables from a .env file.", - "action": "setVariables", - "path": "./secrets.env" - } - ] - } - ] -} -``` From 7cbd4f7f7f020bb41d660ae41cec5dd1d6518e4b Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 15:20:39 -0700 Subject: [PATCH 13/31] Add documentation for `record` and `stopRecord` actions - Create `record.md` to document the recording action and its usage. - Remove outdated `startRecording.md` documentation. - Create `stopRecord.md` to document the stopping action and its usage. - Remove outdated `stopRecording.md` documentation. --- docs/get-started/actions/record.md | 115 +++++++++++++++++++++ docs/get-started/actions/startRecording.md | 14 --- docs/get-started/actions/stopRecord.md | 45 ++++++++ docs/get-started/actions/stopRecording.md | 14 --- 4 files changed, 160 insertions(+), 28 deletions(-) create mode 100644 docs/get-started/actions/record.md delete mode 100644 docs/get-started/actions/startRecording.md create mode 100644 docs/get-started/actions/stopRecord.md delete mode 100644 docs/get-started/actions/stopRecording.md diff --git a/docs/get-started/actions/record.md b/docs/get-started/actions/record.md new file mode 100644 index 00000000..752a0898 --- /dev/null +++ b/docs/get-started/actions/record.md @@ -0,0 +1,115 @@ +--- +title: record +layout: default +nav_order: 1 +parent: Actions +grand_parent: Tests +description: Start capturing a video of test execution. +--- + +# record + +The `record` action starts recording the browser viewport as a video file (MP4, WebM, or GIF). This is useful for debugging failed tests or creating multimedia documentation. Recording continues until a `stopRecord` step is encountered. + +*Note: Recording is currently only supported in visible Chrome browsers.* + +You can specify the recording action in several ways: + +- **Boolean Shorthand:** Set `record: true` to start recording with default settings (usually saved as `record_.mp4` in the output directory). +- **String Shorthand:** Provide a file path directly as the value for the `record` key (e.g., `record: "test_session.webm"`). This starts recording to the specified path. Supported extensions are `.mp4`, `.webm`, and `.gif`. +- **Object Format:** Use an object for more control over the output file: + - `path`: (Optional) The file path where the recording will be saved. Can include directories. If omitted, a default path is generated. + - `directory`: (Optional) The directory where the recording will be saved. If `path` includes a directory, this is ignored. Defaults to the configured output directory. + - `overwrite`: (Optional) Set to `true` to overwrite an existing file at the target path. Defaults to `false`. + +**Stopping the Recording:** You *must* include a `stopRecord` step later in your test to finalize and save the video file. + +> For comprehensive options, see the [`record`](/docs/references/schemas/record) and [`stopRecord`](/docs/references/schemas/stopRecord) references. + +## Examples + +Here are a few ways you might use the `record` and `stopRecord` actions: + +### Simple recording (boolean shorthand) + +Starts recording to a default path like `output/record_1745032062266.mp4` and stops later. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Start recording.", + "record": true + }, + { + "description": "Perform some actions...", + "goTo": "https://example.com" + }, + { + "description": "Stop recording.", + "stopRecord": true + } + ] + } + ] +} +``` + +### Recording to a specific path (string shorthand) + +Records to `./output/media/login_flow.webm`. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Start recording to a specific WebM file.", + "record": "./output/media/login_flow.webm" + }, + { + "description": "...", + "find": "Login" + }, + { + "description": "Stop recording.", + "stopRecord": true + } + ] + } + ] +} +``` + +### Recording with object format (overwrite enabled) + +Records to `test_video.gif` in the `output/gifs` directory, overwriting if it exists. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Start recording a GIF, overwriting if necessary.", + "record": { + "path": "test_video.gif", + "directory": "./output/gifs", + "overwrite": true + } + }, + { + "description": "...", + "wait": 2000 + }, + { + "description": "Stop recording.", + "stopRecord": true + } + ] + } + ] +} diff --git a/docs/get-started/actions/startRecording.md b/docs/get-started/actions/startRecording.md deleted file mode 100644 index e5491b89..00000000 --- a/docs/get-started/actions/startRecording.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: startRecording -layout: default -nav_order: 1 -parent: Actions -grand_parent: Tests -description: Capture a video of test execution. ---- - -# startRecording - -The `startRecording` action records tests as they are run for debugging or multimedia purposes. - -> For comprehensive options, see the [`startRecording`](/docs/references/schemas/startRecording) reference. diff --git a/docs/get-started/actions/stopRecord.md b/docs/get-started/actions/stopRecord.md new file mode 100644 index 00000000..3281bd99 --- /dev/null +++ b/docs/get-started/actions/stopRecord.md @@ -0,0 +1,45 @@ +--- +title: stopRecord +layout: default +nav_order: 1 +parent: Actions +grand_parent: Tests +description: Stop capturing a video of test execution. +--- + +The `stopRecord` action stops a video recording previously started by a [`record`](record) action and saves the video file. + +This action takes a simple boolean value: + +- `stopRecord: true`: Stops the current recording. + +>Note: You must include a `stopRecord: true` step to finalize and save any recording started with the `record` action. +> +> For comprehensive options, see the [`stopRecord`](/docs/references/schemas/stopRecord) reference. + +## Example + +This example starts recording, performs an action, and then stops the recording. + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Start recording.", + "record": "./output/session_video.mp4" + }, + { + "description": "Navigate to the site.", + "goTo": "https://example.com" + }, + { + "description": "Stop the recording.", + "stopRecord": true + } + ] + } + ] +} +``` diff --git a/docs/get-started/actions/stopRecording.md b/docs/get-started/actions/stopRecording.md deleted file mode 100644 index 2578b392..00000000 --- a/docs/get-started/actions/stopRecording.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: stopRecording -layout: default -nav_order: 1 -parent: Actions -grand_parent: Tests -description: Stop capturing a video of test execution. ---- - -# stopRecording - -The `stopRecording` action stops a recording started by a [`startRecording`](startRecording) action. - -> For comprehensive options, see the [`stopRecording`](/docs/references/schemas/stopRecording) reference. From a16c108af6e7763f18ad8f043c701cbd05783d7e Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 15:36:18 -0700 Subject: [PATCH 14/31] Add documentation for `type` action - Introduce `type` action to simulate key presses, including special keys. - Provide detailed instructions on specifying keys using string, array, and object formats. - Include a comprehensive list of special keys and their codes. - Add examples demonstrating the usage of the `type` action in various scenarios. - Remove outdated `typeKeys` documentation. --- docs/get-started/actions/type.md | 191 +++++++++++++++++++++++++++ docs/get-started/actions/typeKeys.md | 182 ------------------------- 2 files changed, 191 insertions(+), 182 deletions(-) create mode 100644 docs/get-started/actions/type.md delete mode 100644 docs/get-started/actions/typeKeys.md diff --git a/docs/get-started/actions/type.md b/docs/get-started/actions/type.md new file mode 100644 index 00000000..5fe5d703 --- /dev/null +++ b/docs/get-started/actions/type.md @@ -0,0 +1,191 @@ +--- +title: type +layout: default +nav_order: 1 +parent: Actions +grand_parent: Tests +description: Type keys, including special keys like Enter. +--- + +The `type` action simulates key presses, including special keys such as Enter. This action is useful for simulating user input, such as filling out a form, navigating a website, or using keyboard shortcuts. It typically requires a preceding `find` or `click` action to focus an input element. + +You can specify the keys to type in several ways: + +- **String Shorthand:** Provide a simple string as the value for the `type` key. +- **Array Shorthand:** Provide an array of strings. Each string in the array is typed sequentially. This allows mixing regular text with [special keys](#special-keys). +- **Object Format:** Use an object for more control: + - `keys`: (Required) A string or an array of strings representing the keys to type. + - `inputDelay`: (Optional) Delay in milliseconds between each key press. Useful for making recordings more legible. + +> For comprehensive options, see the [`type`](/docs/references/schemas/typeKeys) reference. + +## Special keys + +You can use special keys in the `keys` field to simulate non-character key presses. To use a special key, use the key's associated code enclosed in `$` symbols. For example, to simulate pressing the Enter key, use `$ENTER$`. + +Here's a list of special keys you can use: + +| Key | Code | +| -------------- | ------------------ | +| Alt | $ALT$ | +| Backspace | $BACKSPACE$ | +| Cancel | $CANCEL$ | +| Clear | $CLEAR$ | +| Command | $COMMAND$ | +| Control | $CTRL$ | +| Delete | $DELETE$ | +| End | $END$ | +| Enter | $ENTER$ | +| Escape | $ESCAPE$ | +| Help | $HELP$ | +| Home | $HOME$ | +| Insert | $INSERT$ | +| NULL | $NULL$ | +| Page Down | $PAGE_DOWN$ | +| Page Up | $PAGE_UP$ | +| Pause | $PAUSE$ | +| Return | $RETURN$ | +| Shift | $SHIFT$ | +| Space | $SPACE$ | +| Tab | $TAB$ | +| ZenkakuHankaku | $ZANKAKU_HANDKAKU$ | +| Arrow Down | $ARROW_DOWN$ | +| Arrow Left | $ARROW_LEFT$ | +| Arrow Right | $ARROW_RIGHT$ | +| Arrow Up | $ARROW_UP$ | +| Numpad 0 | $NUMPAD_0$ | +| Numpad 1 | $NUMPAD_1$ | +| Numpad 2 | $NUMPAD_2$ | +| Numpad 3 | $NUMPAD_3$ | +| Numpad 4 | $NUMPAD_4$ | +| Numpad 5 | $NUMPAD_5$ | +| Numpad 6 | $NUMPAD_6$ | +| Numpad 7 | $NUMPAD_7$ | +| Numpad 8 | $NUMPAD_8$ | +| Numpad 9 | $NUMPAD_9$ | +| : | $SEMICOLON$ | +| = | $EQUALS$ | +| \* | $MULTIPLY$ | +| + | $ADD$ | +| \| | $SEPARATOR$ | +| - | $SUBSTRACT$ | +| . | $DECIMAL$ | +| / | $DIVIDE$ | +| F1 | $F1$ | +| F2 | $F2$ | +| F3 | $F3$ | +| F4 | $F4$ | +| F5 | $F5$ | +| F6 | $F6$ | +| F7 | $F7$ | +| F8 | $F8$ | +| F9 | $F9$ | +| F10 | $F10$ | +| F11 | $F11$ | +| F12 | $F12$ | + +## Examples + +### Perform a search (array shorthand) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Go to Google", + "goTo": "https://www.google.com" + }, + { + "description": "Find and click the search bar", + "find": { + "selector": "[title=Search]", + "click": true + } + }, + { + "description": "Type search query and press Enter", + "type": ["American Shorthair kittens", "$ENTER$"] + } + ] + } + ] +} +``` + +### Fill credentials from environment variables (string shorthand) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Load credentials", + "loadVariables": ".env" + }, + { + "description": "Go to login page", + "goTo": "https://console.acme.com/login" + }, + { + "description": "Find, click, and type username", + "find": { + "selector": "#username", + "click": true, + "type": "$USERNAME" // Type directly within find + } + }, + { + "description": "Find, click, and type password, then press Enter", + "find": { + "selector": "#password", + "click": true, + "type": ["$PASSWORD", "$ENTER$"] // Type array within find + } + } + ] + } + ] +} +``` + +### Type with an increased delay (object format) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Go to Google", + "goTo": "https://www.google.com" + }, + { + "description": "Start recording", + "record": "recording.webm" + }, + { + "description": "Find and click search bar", + "find": { + "selector": "[title=Search]", + "click": true + } + }, + { + "description": "Type slowly and press Enter", + "type": { + "keys": ["American Shorthair kittens", "$ENTER$"], + "inputDelay": 500 + } + }, + { + "description": "Stop recording", + "stopRecord": true + } + ] + } + ] +} +``` diff --git a/docs/get-started/actions/typeKeys.md b/docs/get-started/actions/typeKeys.md deleted file mode 100644 index ff816211..00000000 --- a/docs/get-started/actions/typeKeys.md +++ /dev/null @@ -1,182 +0,0 @@ ---- -title: typeKeys -layout: default -nav_order: 1 -parent: Actions -grand_parent: Tests -description: Type keys. ---- - -# typeKeys - -The `typeKeys` action registers key presses, including special keys such as Enter. This action is useful for simulating user input, such as filling out a form, navigating a website, or using keyboard shortcuts. - -You can specify `keys` either as a string or as an array of strings. Each character in a string or array is separated is treated as a separate key press, but specifying an array allows you to include both regular and [special](#special-keys) keys. - -> For comprehensive options, see the [`typeKeys`](/docs/references/schemas/typeKeys) reference. - -## Special keys - -You can use special keys in the `keys` field to simulate key presses. To use a special key, use the key's associated code. For example, to simulate pressing the Enter key, use `$Enter$`. - -Here's a list of special keys you can use: - -| Key | Code | -| -------------- | ------------------ | -| Alt | $ALT$ | -| Backspace | $BACKSPACE$ | -| Cancel | $CANCEL$ | -| Clear | $CLEAR$ | -| Command | $COMMAND$ | -| Control | $CTRL$ | -| Delete | $DELETE$ | -| End | $END$ | -| Enter | $ENTER$ | -| Escape | $ESCAPE$ | -| Help | $HELP$ | -| Home | $HOME$ | -| Insert | $INSERT$ | -| NULL | $NULL$ | -| Page Down | $PAGE_DOWN$ | -| Page Up | $PAGE_UP$ | -| Pause | $PAUSE$ | -| Return | $RETURN$ | -| Shift | $SHIFT$ | -| Space | $SPACE$ | -| Tab | $TAB$ | -| ZenkakuHankaku | $ZANKAKU_HANDKAKU$ | -| Arrow Down | $ARROW_DOWN$ | -| Arrow Left | $ARROW_LEFT$ | -| Arrow Right | $ARROW_RIGHT$ | -| Arrow Up | $ARROW_UP$ | -| Numpad 0 | $NUMPAD_0$ | -| Numpad 1 | $NUMPAD_1$ | -| Numpad 2 | $NUMPAD_2$ | -| Numpad 3 | $NUMPAD_3$ | -| Numpad 4 | $NUMPAD_4$ | -| Numpad 5 | $NUMPAD_5$ | -| Numpad 6 | $NUMPAD_6$ | -| Numpad 7 | $NUMPAD_7$ | -| Numpad 8 | $NUMPAD_8$ | -| Numpad 9 | $NUMPAD_9$ | -| : | $SEMICOLON$ | -| = | $EQUALS$ | -| \* | $MULTIPLY$ | -| + | $ADD$ | -| \| | $SEPARATOR$ | -| - | $SUBSTRACT$ | -| . | $DECIMAL$ | -| / | $DIVIDE$ | -| F1 | $F1$ | -| F2 | $F2$ | -| F3 | $F3$ | -| F4 | $F4$ | -| F5 | $F5$ | -| F6 | $F6$ | -| F7 | $F7$ | -| F8 | $F8$ | -| F9 | $F9$ | -| F10 | $F10$ | -| F11 | $F11$ | -| F12 | $F12$ | - -## Examples - -### Perform a search - -```json -{ - "tests": [ - { - "steps": [ - { - "action": "goTo", - "url": "https://www.google.com" - }, - { - "action": "find", - "selector": "[title=Search]", - "click": true - }, - { - "action": "typeKeys", - "keys": ["American Shorthair kittens", "$ENTER$"] - } - ] - } - ] -} -``` - -### Fill credentials from environment variables - -```json -{ - "tests": [ - { - "steps": [ - { - "action": "setVariables", - "path": ".env" - }, - { - "action": "goTo", - "url": "https://console.acme.com/login" - }, - { - "action": "find", - "selector": "#username", - "click": true - }, - { - "action": "typeKeys", - "keys": ["$USERNAME"] - }, - { - "action": "find", - "selector": "#password", - "click": true - }, - { - "action": "typeKeys", - "keys": ["$PASSWORD", "$ENTER$"] - } - ] - } - ] -} -``` - -### Type with an increased delay for legibility in recordings - -```json -{ - "tests": [ - { - "steps": [ - { - "action": "goTo", - "url": "https://www.google.com" - }, - { - "action": "startRecording", - "path": "recording.webm" - }, - { - "action": "find", - "selector": "[title=Search]", - "click": true - }, - { - "action": "typeKeys", - "keys": ["American Shorthair kittens", "$ENTER$"], - "delay": 500 - }, - { - "action": "stopRecording" - } - ] - } - ] -} -``` From 05464ce3ab9092f3084318f7848ee1c6c652a3e5 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 15:40:32 -0700 Subject: [PATCH 15/31] Enhance documentation for `wait` action - Clarify the purpose of the `wait` action and its usage. - Update examples to reflect the correct structure and default duration. - Remove outdated descriptions and ensure consistency in example formatting. --- docs/get-started/actions/wait.md | 52 +++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/docs/get-started/actions/wait.md b/docs/get-started/actions/wait.md index fdf0fe70..fb161a63 100644 --- a/docs/get-started/actions/wait.md +++ b/docs/get-started/actions/wait.md @@ -9,25 +9,63 @@ description: Pause before performing the next action. # wait -The `wait` action pauses before performing the next step. This action is useful for waiting a set duration before continuing a test, such as creating a pause before ending a recording. +The `wait` action pauses test execution for a specified duration before proceeding to the next step. This is useful for adding delays, for example, to allow time for animations to complete or to make recordings easier to follow. -You can specify the `duration` to pause in milliseconds. The default `duration` is 5 seconds. +The value assigned to the `wait` key is the duration to pause in milliseconds. You can provide a number directly. > For comprehensive options, see the [`wait`](/docs/references/schemas/wait) reference. ## Examples +### Wait for 3 seconds + ```json { - "description": "Wait for 5 seconds.", - "action": "wait" + "tests": [ + { + "steps": [ + { + "description": "Perform an action.", + "goTo": "https://example.com" + }, + { + "description": "Wait for 3000 milliseconds (3 seconds).", + "wait": 3000 + }, + { + "description": "Perform the next action.", + "screenshot": "after_wait.png" + } + ] + } + ] } ``` +### Wait for 500 milliseconds + ```json { - "description": "Wait for 500 milliseconds.", - "action": "wait", - "duration": 500 + "tests": [ + { + "steps": [ + { + "description": "Click something.", + "find": { + "selector": "#myButton", + "click": true + } + }, + { + "description": "Wait for half a second.", + "wait": 500 + }, + { + "description": "Check the result.", + "find": "Action complete!" + } + ] + } + ] } ``` From fca9054df80a2ec0b02b720a47dfd8b0859742a4 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 15:41:02 -0700 Subject: [PATCH 16/31] Added headings --- docs/get-started/actions/stopRecord.md | 2 ++ docs/get-started/actions/type.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/get-started/actions/stopRecord.md b/docs/get-started/actions/stopRecord.md index 3281bd99..d62c6bea 100644 --- a/docs/get-started/actions/stopRecord.md +++ b/docs/get-started/actions/stopRecord.md @@ -7,6 +7,8 @@ grand_parent: Tests description: Stop capturing a video of test execution. --- +# stopRecord + The `stopRecord` action stops a video recording previously started by a [`record`](record) action and saves the video file. This action takes a simple boolean value: diff --git a/docs/get-started/actions/type.md b/docs/get-started/actions/type.md index 5fe5d703..41807762 100644 --- a/docs/get-started/actions/type.md +++ b/docs/get-started/actions/type.md @@ -7,6 +7,8 @@ grand_parent: Tests description: Type keys, including special keys like Enter. --- +# type + The `type` action simulates key presses, including special keys such as Enter. This action is useful for simulating user input, such as filling out a form, navigating a website, or using keyboard shortcuts. It typically requires a preceding `find` or `click` action to focus an input element. You can specify the keys to type in several ways: From bd605b1aff316af37d7fbc53d3d1210874e3cbcb Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 15:48:48 -0700 Subject: [PATCH 17/31] Updated contexts --- docs/get-started/config/contexts/index.md | 376 +++++++++------------- 1 file changed, 148 insertions(+), 228 deletions(-) diff --git a/docs/get-started/config/contexts/index.md b/docs/get-started/config/contexts/index.md index 8f3e892b..21ffdf37 100644 --- a/docs/get-started/config/contexts/index.md +++ b/docs/get-started/config/contexts/index.md @@ -3,16 +3,18 @@ title: Contexts layout: default nav_order: 1 parent: Configuration -description: A set of conditions that must be met for a test to run. +description: Define the contexts (platform and browser combinations) where tests should run. --- # Contexts -Doc Detective uses contexts to determine which tests to run. A context is a set of conditions that must be met in order for a test to run. For example, a context might specify that a test should only run in Safari on macOS. +Doc Detective uses contexts to determine *where* tests should run. A context defines a combination of a target platform (operating system) and, optionally, a target browser with specific configurations. -By default, Doc Detective runs tests in Chrome on Windows, macOS, and Linux. You can specify custom contexts to run tests in other apps. +By default, if contexts are needed but not specified, Doc Detective attempts to find a supported browser (like Chrome or Firefox) on the current platform (Windows, macOS, or Linux) and run tests there. -Each context is made up of an `app` object and a `platforms` array. When Doc Detective runs tests, it checks the associated contexts to see if the app is available and if it's running on a specified platform. If the conditions are met, the test runs in that context. You can specify multiple contexts for a test, and Doc Detective will run the test in each context that is met. +You define contexts using an array of context objects. Each context object specifies the target `platforms` (as a string or array) and the target `browsers` (as a string, array, or object). + +When Doc Detective runs tests, it evaluates the defined contexts against the current environment. If the current platform matches one specified in a context, and if a browser is specified and available, the test runs in that specific browser on that platform. You can specify multiple contexts, and Doc Detective will attempt to run the relevant tests in each matching context. For comprehensive options, see the [context](/docs/references/schemas/context) reference. @@ -20,375 +22,293 @@ For comprehensive options, see the [context](/docs/references/schemas/context) r You can specify contexts at three different levels, in order of precedence: -- **Config**: You can specify contexts in the [`config`](/docs/references/schemas/config) object. These contexts apply to all tests in the suite. -- **Spec**: You can specify contexts in a [`specification`](/docs/references/schemas/specification) object. These contexts override config-level contexts and apply to all tests in the spec. -- **Test**: You can specify contexts in a [`test`](/docs/references/schemas/test) object. These contexts override config- and spec-level contexts and apply only to that test. +- **Config**: Contexts defined in the main [`config`](/docs/references/schemas/config) apply to all tests unless overridden. +- **Spec**: Contexts defined in a [`specification`](/docs/references/schemas/specification) override config-level contexts and apply to all tests within that spec unless overridden. +- **Test**: Contexts defined within a specific [`test`](/docs/references/schemas/test) override config- and spec-level contexts and apply only to that test. -When you specify contexts, you use a `contexts` array. For example, the following JSON specifies three contexts: +Contexts are defined using a `runOn` array containing context objects. For example: ```json { ... - "contexts": [ + "runOn": [ { - "app": { - "name": "chrome" - }, - "platforms": ["windows","mac","linux"] + "platforms": ["windows", "mac", "linux"], + "browsers": "chrome" }, { - "app": { - "firefox" - }, - "platforms": ["windows","mac","linux"] + "platforms": ["windows", "mac", "linux"], + "browsers": "firefox" }, { - "app": { - "name": "safari" - }, - "platforms": ["mac"] + "platforms": "mac", + "browsers": "webkit" // or "safari" } ], ... } ``` -## Apps +## Browsers + +Doc Detective can perform browser-based tests on several browser engines. The following browser names are supported in the `browsers` property: -Doc Detective can perform tests on a variety of apps. The following apps are supported: +- **Chrome** (`chrome`): Uses Chromium. +- **Firefox** (`firefox`): Uses Firefox. +- **WebKit** (`webkit`): Uses WebKit. The name `safari` can be used as an alias for `webkit`. -- [Chrome](#chrome) (`chrome`) -- [Firefox](#firefox) (`firefox`) -- [Safari](#safari) (`safari`) -- [Edge](#edge) (`edge`) -### Chrome +### Chrome (`chrome`) -Chrome is available on Windows, macOS, and Linux. Doc Detective manages and runs a Chrome instance internally, so you don't need to install anything extra. +Available on Windows, macOS, and Linux. -Chrome is the only browser that supports recording test runs with the [`startRecording`](/docs/references/schemas/startRecording) action. +Chrome is the only browser that currently supports video recording via the [`record`](/docs/get-started/actions/record) action. -Here's a basic Chrome context: +Here's a basic Chrome context for all platforms: ```json { - "app": { - "name": "chrome" - }, - "platforms": ["windows", "mac", "linux"] + "platforms": ["windows", "mac", "linux"], + "browsers": "chrome" } ``` -#### Dimensions and visibility - -You can specify the browser dimensions and visibility (`headless`) during tests. `headless` must be `false` to record test runs. +Or using the object format: ```json { - "app": { - "name": "chrome", - "options": { - "width": 1024, - "height": 768, - "headless": false - } - }, - "platforms": ["windows", "mac", "linux"] + "platforms": ["windows", "mac", "linux"], + "browsers": { + "name": "chrome" + } } ``` -#### Custom path +#### Chrome Dimensions and Visibility -You can specify a Chrome installation on your system if you want to use a specific version of Chrome or a Chromium derivative. If you specify a custom path, you must also specify a path to a matching ChromeDriver executable. For example: +You can specify browser window dimensions, viewport dimensions, and visibility (`headless`). `headless` must be `false` (i.e., run in headed mode) to use the `record` action. ```json { - "app": { + "platforms": ["windows", "mac", "linux"], + "browsers": { "name": "chrome", - "options": { - "path": "/path/to/chrome", - "driverPath": "/path/to/chromedriver" + "headless": false, // Required for recording + "window": { + "width": 1280, + "height": 800 + }, + "viewport": { + "width": 1200, + "height": 720 } - }, - "platforms": ["windows", "mac", "linux"] + } } ``` -### Firefox +### Firefox (`firefox`) -Firefox is available on Windows, macOS, and Linux. Doc Detective manages and runs a Firefox instance internally, so you don't need to install anything extra. +Available on Windows, macOS, and Linux. Here's a basic Firefox context: ```json { - "app": { - "name": "firefox" - }, - "platforms": ["windows", "mac", "linux"] -} -``` - -#### Dimensions and visibility - -You can specify the browser dimensions and visibility (`headless`) during tests. - -```json -{ - "app": { - "name": "chrome", - "options": { - "width": 1024, - "height": 768, - "headless": false - } - }, - "platforms": ["windows", "mac", "linux"] + "platforms": ["windows", "mac", "linux"], + "browsers": "firefox" } ``` -#### Custom path +#### Firefox Dimensions and Visibility -You can specify a Firefox installation on your system if you want to use a specific version of Firefox or a Firefox derivative. For example: +You can specify dimensions and visibility (`headless`). ```json { - "app": { + "platforms": ["windows", "mac", "linux"], + "browsers": { "name": "firefox", - "options": { - "path": "/path/to/firefox" + "headless": true, + "window": { + "width": 1024, + "height": 768 } - }, - "platforms": ["windows", "mac", "linux"] + } } ``` -### Safari - -Safari is only available on macOS. Doc Detective runs tests in a sandboxed instance of your local Safari browser. - -Before you run tests on Safari, you need to enable SafariDriver with the following command in a terminal: - -```bash -safaridriver --enable -``` - -**Note:** SafariDriver is enabled by default in GitHub Actions. - -If Doc Detective isn't running tests in Safari, make sure +### WebKit (`webkit` or `safari`) -- SafariDriver is enabled. -- the **Enable automation** option is selected the Safari's **Develop** menu. +WebKit testing is primarily associated with Safari on macOS. Doc Detective runs tests using the WebKit driver. -#### Dimensions +You can use either `webkit` or `safari` as the browser name. -You can specify the browser dimensions during tests. +Before running tests with WebKit/Safari on macOS, you might need to enable the driver: -**Note:** Safari doesn't support headless mode. +1. Run `safaridriver --enable` in your terminal. +2. Ensure **Develop > Allow Remote Automation** is checked in Safari's menu bar (you might need to enable the Develop menu first in Safari's Advanced preferences). -```json -{ - "app": { - "name": "safari", - "options": { - "width": 1024, - "height": 768 - } - }, - "platforms": ["mac"] -} -``` - -### Edge +*Note: This setup is often handled automatically in CI environments like GitHub Actions.* -Edge is available on Windows, macOS, and Linux. edge is installed by default on Windows, but you must manually install it on macOS and Linux. If Edge is installed, Doc Detective can automatically detect and run tests in your local installation. - -Here's a basic Edge context: +Here's a basic WebKit/Safari context for macOS: ```json { - "app": { - "name": "edge" - }, - "platforms": ["windows", "mac", "linux"] + "platforms": "mac", + "browsers": "webkit" // or "safari" } ``` -#### Dimensions and visibility +#### WebKit/Safari Dimensions -You can specify the browser dimensions and visibility (`headless`) during tests. +You can specify window or viewport dimensions. WebKit/Safari does **not** support headless mode. ```json { - "app": { - "name": "edge", - "options": { - "width": 1024, - "height": 768, - "headless": false + "platforms": "mac", + "browsers": { + "name": "webkit", // or "safari" + "headless": false, // Headless is not supported + "viewport": { + "width": 1440, + "height": 900 } - }, - "platforms": ["windows", "mac", "linux"] + } } ``` ## Platforms -Doc Detective can perform tests on a variety of platforms. The following platforms are supported: +Doc Detective can run tests targeting the following platforms: - Windows (`windows`) - macOS (`mac`) -- Linux (tested on Ubuntu) (`linux`) +- Linux (`linux`) (Tested primarily on Ubuntu) -When you specify a platform for a context, Doc Detective attempts to run associated tests when the context is executed on that platform. If a platform isn't specified, Doc Detective attempts to run the tests on all platforms. +When you specify a platform (or multiple platforms) in a context, Doc Detective attempts to run the associated tests only when executed on a matching operating system. If `platforms` is omitted, it defaults to the current platform. -For example, the following context specifies that tests should only run on macOS: +For example, this context targets only macOS: ```json { - "app": { - "name": "chrome" - }, - "platforms": ["mac"] + "platforms": "mac", + "browsers": "chrome" } ``` -## Examples +This context targets Windows or Linux: -### Contexts - -Here are some examples of contexts: +```json +{ + "platforms": ["windows", "linux"], + "browsers": "firefox" +} +``` -- Run tests in Chrome on Windows, macOS, and Linux: +## Examples - ```json - { - "app": { - "name": "chrome" - }, - "platforms": ["windows", "mac", "linux"] - } - ``` +### Simple Contexts -- Run tests in Firefox on Windows and macOS: +- Run tests in Chrome on all supported platforms: ```json { - "app": { - "name": "firefox" - }, - "platforms": ["windows", "mac"] + "platforms": ["windows", "mac", "linux"], + "browsers": "chrome" } ``` -- Run tests in Safari on macOS: +- Run tests in Firefox on Windows and macOS: ```json { - "app": { - "name": "safari" - }, - "platforms": ["mac"] + "platforms": ["windows", "mac"], + "browsers": "firefox" } ``` -- Run tests in Edge on Windows: +- Run tests in WebKit/Safari on macOS: ```json { - "app": { - "name": "edge" - }, - "platforms": ["windows"] + "platforms": "mac", + "browsers": "webkit" // or "safari" } ``` -### In a config - -You can specify contexts in the `config` object. These contexts apply to all tests in the suite. +### Contexts in a Config (`config.json`) -- Run all tests in each of the apps that are available by default on each platform: +Specify contexts in the top-level `runOn` array. These apply to all tests unless overridden. - ```json - { - "input": ".", - "contexts": [ - { - "app": { - "name": "chrome" - }, - "platforms": ["windows", "mac", "linux"] - }, - { - "app": { - "name": "firefox" - }, - "platforms": ["windows", "mac", "linux"] - }, - { - "app": { - "name": "safari" - }, - "platforms": ["mac"] - }, - { - "app": { - "name": "edge" - }, - "platforms": ["windows"] +```json +{ + "input": ".", + "output": "output", + "runOn": [ + { + "platforms": ["windows", "mac", "linux"], + "browsers": "chrome" + }, + { + "platforms": ["windows", "mac", "linux"], + "browsers": "firefox" + }, + { + "platforms": "mac", + "browsers": { + "name": "webkit", + "window": { "width": 1280, "height": 800 } } - ] - } - ``` - -### In a specification + } + ] +} +``` -You can specify contexts in the `specification` object. These contexts override config-level contexts and apply to all tests in the spec. +### Contexts in a Specification (`*.spec.json`) -This example runs all tests in the spec with Chrome on Windows and macOS: +Specify contexts in the spec's `runOn` array. These override config-level contexts for tests within this spec. ```json { - "contexts": [ + "description": "Specification for login tests", + "runOn": [ { - "app": { - "name": "chrome" - }, - "platforms": ["windows","mac"] + "platforms": ["windows", "mac"], + "browsers": "chrome" } ], "tests": [ - ... + // ... tests in this spec will run on Chrome on Windows & Mac ] } ``` -### In a test - -You can specify contexts in the `test` object. These contexts override config- and spec-level contexts and apply only to that test. +### Contexts in a Test -This example runs a single test in Chrome on Windows: +Specify contexts in the test's `runOn` array. These override config- and spec-level contexts for this specific test. ```json { - "name": "Spec name", + "description": "Main application specification", "tests": [ { - "name": "Test name", - "contexts": [ + "description": "Test login form on Windows/Chrome only", + "runOn": [ { - "app": { - "name": "chrome" - }, - "platforms": ["windows"] + "platforms": "windows", + "browsers": "chrome" } ], "steps": [ - ... + // ... steps for this test ] }, { - ... + "description": "Test dashboard on all default contexts", + // No runOn here, inherits from spec or config + "steps": [ + // ... steps for this test + ] } ] } From e199d475a4068296fb80bdfdeee2538c643b99fc Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 19:35:44 -0700 Subject: [PATCH 18/31] Update test documentation and action definitions - Clarify steps and actions in the test specification section. - Add new actions: `click`, `loadVariables`, `record`, `stopRecord`, and `screenshot`. - Update action references in examples to reflect new naming conventions. - Improve inline JSON examples for better clarity. --- docs/get-started/tests/index.md | 125 +++++++++++++++----------------- 1 file changed, 58 insertions(+), 67 deletions(-) diff --git a/docs/get-started/tests/index.md b/docs/get-started/tests/index.md index c2ad38e7..77ffe755 100644 --- a/docs/get-started/tests/index.md +++ b/docs/get-started/tests/index.md @@ -11,19 +11,21 @@ Tests tell Doc Detective what actions to perform, how, and where. Tests are made - **Test specification**: The highest-level component, test specifications (or specs) are collection of tests that should run together. [Contexts](/docs/get-started/config/contexts) defined in the spec are shared by all tests in the spec. Test specifications are equivalent to test suites in other testing frameworks. - **Test**: A test to run within a spec. Each test has a name, and a set of steps to perform. Tests are equivalent to test cases in other testing frameworks. -- **Steps**: A step is a single action to perform within a test. Each individual step acts as an assertion that the step completes as expected. Steps are equivalent to assertions in other testing frameworks. +- **Steps**: A step is a single action to perform within a test. Each individual step acts as an assertion that the step completes as expected. Steps are roughly equivalent to assertions in other testing frameworks. - Each step has an action, which is a command that tells Doc Detective what to do. Actions can have additional properties that further define the action. + Each step can perform an action, which is a command that tells Doc Detective what to do. Actions can have additional properties that further define the action. - [**checkLink**](/docs/get-started/actions/checkLink): Check if a URL returns an acceptable status code from a GET request. + - [**click**](/docs/get-started/actions/click): Click or tap an element. - [**find**](/docs/get-started/actions/find): Check if an element exists with the specified selector. - [**goTo**](/docs/get-started/actions/goTo): Navigate to a specified URL. - [**httpRequest**](/docs/get-started/actions/httpRequest): Perform a generic HTTP request, for example to an API. + - [**loadVariables**](/docs/get-started/actions/loadVariables): Load environment variables from a `.env` file. + - [**record**](/docs/get-started/actions/record) and [**stopRecord**](/docs/get-started/actions/stopRecord): Capture a video of test execution. + - [**runCode**](/docs/get-started/actions/runCode): Assemble and run code. - [**runShell**](/docs/get-started/actions/runShell): Perform a native shell command. - - [**saveScreenshot**](/docs/get-started/actions/saveScreenshot): Take a screenshot in PNG format. - - [**setVariables**](/docs/get-started/actions/setVariables): Load environment variables from a `.env` file. - - [**startRecording**](/docs/get-started/actions/startRecording) and [**stopRecording**](/docs/get-started/actions/stopRecording): Capture a video of test execution. - - [**typeKeys**](/docs/get-started/actions/typeKeys): Type keys. To type special keys, begin and end the string with `$` and use the special key’s enum. For example, to type the Escape key, enter `$ESCAPE$`. + - [**screenshot**](/docs/get-started/actions/screenshot): Take a screenshot in PNG format. + - [**type**](/docs/get-started/actions/type): Type keys. To type special keys, begin and end the string with `$` and use the special key’s enum. For example, to type the Escape key, enter `$ESCAPE$`. - [**wait**](/docs/get-started/actions/wait): Pause before performing the next action. ## Define a test @@ -40,18 +42,17 @@ Test specs in standalone JSON files use the following basic structure: ```json { - "id": "spec-id", + "specId": "spec-id", "description": "Spec Description", "tests": [ { - "id": "test-id", + "testId": "test-id", "description": "Test Description", "steps": [ { - "id": "step-id", + "stepId": "step-id", "description": "Step Description", - "action": "action-name" - // Additional step properties + // Additional step properties, such as find, goTo, httpRequest, etc. } ] } @@ -69,25 +70,22 @@ Here's an example test for performing a Google search and saving a screenshot of { "steps": [ { - "action": "goTo", - "url": "https://www.google.com" + "goTo": "https://www.google.com" }, { - "action": "find", - "selector": "[title=Search]", - "click": true + "find": { + "selector": "[title=Search]", + "click": true + } }, { - "action": "typeKeys", - "keys": ["American Shorthair kittens", "$ENTER$"] + "type": ["American Shorthair kittens", "$ENTER$"] }, { - "action": "wait", - "duration": 5000 + "wait": 5000 }, { - "action": "saveScreenshot", - "path": "search-results.png" + "screenshot": "search-results.png" } ] } @@ -118,23 +116,23 @@ If you declare a step without declaring a test, Doc Detective automatically crea Here's an example of an inline test for performing a Google search and saving a screenshot of the results: ```markdown -[comment]: # 'test {"id": "kitten-search"}' +[comment]: # 'test {"testId": "kitten-search"}' To search for American Shorthair kittens, 1. Go to [Google](https://www.google.com). - [comment]: # 'step {"action":"goTo", "url":"https://www.google.com"}' + [comment]: # 'step {"goTo": "https://www.google.com"}' 2. In the search bar, enter "American Shorthair kittens", then press Enter. - [comment]: # 'step { "action": "find", "selector": "[title=Search]", "click": true }' - [comment]: # 'step { "action": "typeKeys", "keys": ["American Shorthair kittens", "$ENTER$"] }' - [comment]: # 'step { "action": "wait", "duration": 5000 }' + [comment]: # 'step { "find": { "selector": "[title=Search]", "click": true } }' + [comment]: # 'step { "type": ["American Shorthair kittens", "$ENTER$"] }' + [comment]: # 'step { "wait": 5000 }' ![Search results](search-results.png) -[comment]: # 'step { "action": "saveScreenshot", "path": "search-results.png" }' +[comment]: # 'step { "screenshot": "search-results.png" }' [comment]: # "test end" ``` @@ -231,17 +229,16 @@ Detected tests: { "steps": [ { - "action": "goTo", - "url": "https://console.acme.com" + "goTo": "https://console.acme.com" }, { - "action": "find", - "selector": "aria/Search", - "click": true + "find": { + "selector": "aria/Search", + "click": true + } }, { - "action": "saveScreenshot", - "path": "search-results.png" + "screenshot": "search-results.png" } ] } @@ -261,8 +258,7 @@ Check that the match returns a valid status code. ```json { - "action": "checkLink", - "url": "$1" + "checkLink": "$1" } ``` @@ -272,8 +268,7 @@ Open the match as a URL in a browser. ```json { - "action": "goTo", - "url": "$1" + "goTo": "$1" } ``` @@ -283,30 +278,29 @@ Find an element on the current page that has an ARIA label that equals the match ```json { - "action": "find", - "selector": "aria/$1" + "find": { + "selector": "aria/$1" + } } ``` -#### `saveScreenshot` +#### `screenshot` Save a screenshot to a path equalling the match. ```json { - "action": "saveScreenshot", - "path": "$1" + "screenshot": "$1" } ``` -#### `typeKeys` +#### `type` Type the match into the current page. ```json { - "action": "typeKeys", - "keys": "$1" + "type": "$1" } ``` @@ -316,8 +310,7 @@ Make an GET request to the match. ```json { - "action": "httpRequest", - "url": "$1" + "httpRequest": "$1" } ``` @@ -327,29 +320,27 @@ Run the match as a shell command. ```json { - "action": "runShell", - "command": "$1" + "runShell": "$1" } ``` -#### `startRecording` +#### `record` Start recording a video to a path equalling the match. ```json { - "action": "startRecording", - "path": "$1" + "record": "$1" } ``` -#### `stopRecording` +#### `stopRecord` Stop recording a video. ```json { - "action": "stopRecording" + "stopRecord": true } ``` @@ -359,36 +350,36 @@ Wait for the specified duration. ```json { - "action": "wait", - "duration": "$1" + "wait": { + "duration": "$1" + } } ``` -#### `setVariables` +#### `loadVariables` Load environment variables from an `.env` file, where the path is the match. ```json { - "action": "setVariables", - "path": "$1" + "loadVariables": "$1" } ``` ## Run tests -Doc Detective's `runTest` command runs your tests. Input files are read from your config's `input` and `runTests.input` properties, but you can also specify input files directly in the command with the `--input` flag. +Doc Detective's `doc-detective` command runs your tests. Input files are read from your config's `input` property, but you can also specify input files directly in the command with the `--input` flag. This example runs all test specs in your config's `input` and `runTest.input` parameters: ```bash -npx doc-detective runTests +npx doc-detective ``` This example runs all test specs in a file named `doc-content.md` in the `samples` directory: ```bash -npx doc-detective runTests --input ./samples/doc-content.md +npx doc-detective --input ./samples/doc-content.md ``` ### Remotely hosted tests @@ -396,15 +387,15 @@ npx doc-detective runTests --input ./samples/doc-content.md You can run tests hosted remotely by specifying the URL of the test file with the `--input` argument. For example, to run tests from a file hosted at `https://doc-detective.com/sample.spec.json`, run the following command: ```bash -npx doc-detective runTests --input https://doc-detective.com/sample.spec.json +npx doc-detective --input https://doc-detective.com/sample.spec.json ``` These tests run the same way as local tests, but Doc Detective fetches the test file from the specified URL and stores it in a temporary directory. The URL must be accessible to the machine running the tests. ## Read the results -Doc Detective outputs test results to a `testResults-.json` file in your `output` or `runTests.output` directory. You can also specify your output directory with the `--output` flag: +Doc Detective outputs test results to a `testResults-.json` file in your `output` directory. You can also specify your output directory with the `--output` flag: ```bash -npx doc-detective runTests --input ./samples/doc-content.md --output ./samples/ +npx doc-detective --input ./samples/doc-content.md --output ./samples/ ``` From c00910df33a6d19c889b27a233108d108b167fd2 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 21 Apr 2025 19:41:09 -0700 Subject: [PATCH 19/31] Refactor action definitions in test markup - Remove deprecated "runTests" property. - Update "Click" action to use "find" object. - Change "saveScreenshot" action to use "screenshot" object. --- docs/get-started/tests/index.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/get-started/tests/index.md b/docs/get-started/tests/index.md index 77ffe755..f1a0c5bf 100644 --- a/docs/get-started/tests/index.md +++ b/docs/get-started/tests/index.md @@ -149,11 +149,10 @@ For example, markup for Markdown files might look like this: ```json { ... - "runTests": { - "detectSteps": true - }, "fileTypes": [ { + "name": "Markdown", + "extensions": ["md", "markdown", "mdx"], ... "markup": [ { @@ -177,10 +176,10 @@ For example, markup for Markdown files might look like this: "name": "Click", "regex": ["(?:[Cc]lick|[Pp]ress|[Cc]hoose|[Tt]ap)\\s+\\*\\*(.+?)\\*\\*"], "actions": [{ - "action": "find", - "description": "Click $1", - "selector": "aria/$1", - "click": true + "find": { + "selector": "aria/$1", + "click": true + } }] }, { @@ -188,11 +187,12 @@ For example, markup for Markdown files might look like this: "regex": ["!\\[.+?\\]\\((.+?)\\)"], "actions": [ { - "action": "saveScreenshot", - "path": "$1", - "directory": "samples", - "maxVariation": 5, - "overwrite": "byVariation" + "screenshot": { + "path": "$1", + "directory": "samples", + "maxVariation": 5, + "overwrite": "byVariation" + } } ] } From e11f95bfed2c0888114ccea0b353446bffe9c51c Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Wed, 23 Apr 2025 19:29:37 -0700 Subject: [PATCH 20/31] Add new click page --- docs/get-started/actions/click.md | 135 ++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 docs/get-started/actions/click.md diff --git a/docs/get-started/actions/click.md b/docs/get-started/actions/click.md new file mode 100644 index 00000000..611bd9ab --- /dev/null +++ b/docs/get-started/actions/click.md @@ -0,0 +1,135 @@ +--- +title: click +layout: default +nav_order: 2 +parent: Actions +grand_parent: Tests +description: Click or tap an element on the page. +--- + +# click + +The `click` action allows you to click or tap an element on the page. You can specify which mouse button to use and target elements using text or selectors. + +The `click` action works in several ways: +- **Boolean Shorthand:** Set to `true` to perform a standard left click on the active element. +- **String Shorthand:** Specify the button type directly as `"left"`, `"right"`, or `"middle"`. +- **Object Format:** Use an object with detailed properties for more control over the click action. + +If you need to find an element before clicking it, consider using the [`find`](/docs/get-started/actions/find) action, which lets you locate elements and optionally click them in a single step. + +**Note:** If you use the `click` action without the `find` action, it will click the active element or the element at the current cursor position. + +## Properties + +When using the object format, you can specify: + +- `button`: (Optional) Which mouse button to use. Can be `"left"`, `"right"`, or `"middle"`. Default is `"left"`. +- `selector`: (Optional) CSS or XPath selector of the element to click. If combined with `elementText`, the element must match both. +- `elementText`: (Optional) Display text of the element to click. If combined with `selector`, the element must match both. + +> For comprehensive options, see the full [`click`](/docs/references/schemas/click) reference. + +## Examples + +Here are a few ways you might use the `click` action: + +### Simple left click (boolean shorthand) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Click the currently focused element", + "click": true + } + ] + } + ] +} +``` + +### Specify button type (string shorthand) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Right-click the currently focused element", + "click": "right" + } + ] + } + ] +} +``` + +### Click an element by text (object format) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Left-click on a button with specific text", + "click": { + "button": "left", + "elementText": "Submit" + } + } + ] + } + ] +} +``` + +### Click an element by selector (object format) + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Middle-click on an element with a specific selector", + "click": { + "selector": "#open-in-new-tab", + "button": "middle" + } + } + ] + } + ] +} +``` + +### Click an element by both selector and text + +```json +{ + "tests": [ + { + "steps": [ + { + "description": "Click on a specific element matching both selector and text", + "click": { + "selector": ".btn", + "elementText": "Download", + "button": "left" + } + } + ] + } + ] +} +``` + +## Related Actions + +- [`find`](/docs/get-started/actions/find): Find an element and optionally interact with it +- [`type`](/docs/get-started/actions/type): Type text or special keys From 529d03e2ce37576f8dd2b761e790f0f02cc22adf Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Wed, 23 Apr 2025 19:29:46 -0700 Subject: [PATCH 21/31] Update action definitions in concepts documentation - Replace old action names with updated ones - Modify descriptions for clarity - Ensure consistency in action terminology --- docs/get-started/concepts.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/get-started/concepts.md b/docs/get-started/concepts.md index 0859c9bf..5f049213 100644 --- a/docs/get-started/concepts.md +++ b/docs/get-started/concepts.md @@ -22,19 +22,20 @@ A step is a portion of a test that includes a single action. Conceptually parall An action is the task performed in a step. Doc Detective supports a variety of actions: -| Name | Description | -| :------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [checkLink](/docs/get-started/actions/checkLink.md) | Check if a URL returns an acceptable status code from a GET request. | -| [find](/docs/get-started/actions/find.md) | Locate and interact with an element on the page. | -| [goTo](/docs/get-started/actions/goTo.md) | Navigate to a specified URL. | -| [httpRequest](/docs/get-started/actions/httpRequest.md) | Perform a generic HTTP request, for example to an API. | -| [runShell](/docs/get-started/actions/runShell.md) | Perform a native shell command. | -| [saveScreenshot](/docs/get-started/actions/saveScreenshot.md) | Take a screenshot in PNG format. | -| [setVariables](/docs/get-started/actions/setVariables.md) | Load environment variables from a `.env` file. | -| [startRecording](/docs/get-started/actions/startRecording.md) | Capture a video of test run. | -| [stopRecording](/docs/get-started/actions/stopRecording.md) | Stop capturing a video of test run. | -| [typeKeys](/docs/get-started/actions/typeKeys.md) | Type keys. To type special keys, begin and end the string with `$` and use the special key’s enum. For example, to type the Escape key, enter `$ESCAPE$`. | -| [wait](/docs/get-started/actions/wait.md) | Pause before performing the next action. | +| Name | Description | +| :---------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [checkLink](/docs/get-started/actions/checkLink.md) | Check if a URL returns an acceptable status code from a GET request. | +| [find](/docs/get-started/actions/find.md) | Locate and interact with an element on the page. | +| [click](/docs/get-started/actions/click.md) | Click an element. | +| [goTo](/docs/get-started/actions/goTo.md) | Navigate to a specified URL. | +| [httpRequest](/docs/get-started/actions/httpRequest.md) | Perform a generic HTTP request, for example to an API. | +| [runShell](/docs/get-started/actions/runShell.md) | Perform a native shell command. | +| [screenshot](/docs/get-started/actions/screenshot.md) | Take a screenshot in PNG format. | +| [loadVariables](/docs/get-started/actions/loadVariables.md) | Load environment variables from a `.env` file. | +| [record](/docs/get-started/actions/record.md) | Capture a video of test run. | +| [stopRecord](/docs/get-started/actions/stopRecord.md) | Stop capturing a video of test run. | +| [type](/docs/get-started/actions/type.md) | Type keys. To type special keys, begin and end the string with `$` and use the special key’s enum. For example, to type the Escape key, enter `$ESCAPE$`. | +| [wait](/docs/get-started/actions/wait.md) | Pause before performing the next action. | ## Context From 5cdc13816601280004ec2dad709fdba6d43960fc Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Wed, 23 Apr 2025 19:29:57 -0700 Subject: [PATCH 22/31] Refactor test documentation for clarity and consistency - Remove unnecessary braces in JSON examples - Update action descriptions for clarity - Standardize formatting of JSON snippets - Improve inline instructions for better readability --- docs/get-started/tests/index.md | 67 +++++++++++---------------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/docs/get-started/tests/index.md b/docs/get-started/tests/index.md index f1a0c5bf..c15e6f86 100644 --- a/docs/get-started/tests/index.md +++ b/docs/get-started/tests/index.md @@ -51,7 +51,7 @@ Test specs in standalone JSON files use the following basic structure: "steps": [ { "stepId": "step-id", - "description": "Step Description", + "description": "Step Description" // Additional step properties, such as find, goTo, httpRequest, etc. } ] @@ -214,9 +214,9 @@ Markdown: To get started, 1. Go to [Acme Console](https://console.acme.com). -2. Press **Search**. +2. Click **Search**. -![Search results](search-results.png) +![Search results](search-results.png){ .screenshot } ``` @@ -232,10 +232,7 @@ Detected tests: "goTo": "https://console.acme.com" }, { - "find": { - "selector": "aria/Search", - "click": true - } + "click": "Search" }, { "screenshot": "search-results.png" @@ -257,9 +254,15 @@ The default actions are as follows: Check that the match returns a valid status code. ```json -{ - "checkLink": "$1" -} +{ "checkLink": "$1" } +``` + +### `click` + +Click or tap the match. + +```json +{ "click": "$1" } ``` #### `goTo` @@ -267,9 +270,7 @@ Check that the match returns a valid status code. Open the match as a URL in a browser. ```json -{ - "goTo": "$1" -} +{ "goTo": "$1" } ``` #### `find` @@ -277,11 +278,7 @@ Open the match as a URL in a browser. Find an element on the current page that has an ARIA label that equals the match. ```json -{ - "find": { - "selector": "aria/$1" - } -} +{ "find": "$1" } ``` #### `screenshot` @@ -289,9 +286,7 @@ Find an element on the current page that has an ARIA label that equals the match Save a screenshot to a path equalling the match. ```json -{ - "screenshot": "$1" -} +{ "screenshot": "$1" } ``` #### `type` @@ -299,9 +294,7 @@ Save a screenshot to a path equalling the match. Type the match into the current page. ```json -{ - "type": "$1" -} +{ "type": "$1" } ``` #### `httpRequest` @@ -309,9 +302,7 @@ Type the match into the current page. Make an GET request to the match. ```json -{ - "httpRequest": "$1" -} +{ "httpRequest": "$1" } ``` #### `runShell` @@ -319,9 +310,7 @@ Make an GET request to the match. Run the match as a shell command. ```json -{ - "runShell": "$1" -} +{ "runShell": "$1" } ``` #### `record` @@ -329,9 +318,7 @@ Run the match as a shell command. Start recording a video to a path equalling the match. ```json -{ - "record": "$1" -} +{ "record": "$1" } ``` #### `stopRecord` @@ -339,9 +326,7 @@ Start recording a video to a path equalling the match. Stop recording a video. ```json -{ - "stopRecord": true -} +{ "stopRecord": true } ``` #### `wait` @@ -349,11 +334,7 @@ Stop recording a video. Wait for the specified duration. ```json -{ - "wait": { - "duration": "$1" - } -} +{ "wait": "$1" } ``` #### `loadVariables` @@ -361,9 +342,7 @@ Wait for the specified duration. Load environment variables from an `.env` file, where the path is the match. ```json -{ - "loadVariables": "$1" -} +{ "loadVariables": "$1" } ``` ## Run tests From a79ec4bec2b92b54bc3beb5f3be5bc04718137d0 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Wed, 23 Apr 2025 19:30:18 -0700 Subject: [PATCH 23/31] Update actions in sidebar configuration - Add 'click' action to the Actions category - Replace 'saveScreenshot', 'setVariables', 'startRecording', 'stopRecording', and 'typeKeys' with 'screenshot', 'loadVariables', 'record', 'stopRecord', and 'type' --- sidebars.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sidebars.ts b/sidebars.ts index 776c78de..2a9e67a7 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -36,15 +36,16 @@ const sidebars: SidebarsConfig = { link: {type: 'generated-index', description: 'Actions are the commands performed in each step of a test. Each action has a specific purpose, such as checking a link, finding an element, or navigating to a URL.'}, items: [ 'get-started/actions/checkLink', + 'get-started/actions/click', 'get-started/actions/find', 'get-started/actions/goTo', 'get-started/actions/httpRequest', 'get-started/actions/runShell', - 'get-started/actions/saveScreenshot', - 'get-started/actions/setVariables', - 'get-started/actions/startRecording', - 'get-started/actions/stopRecording', - 'get-started/actions/typeKeys', + 'get-started/actions/screenshot', + 'get-started/actions/loadVariables', + 'get-started/actions/record', + 'get-started/actions/stopRecord', + 'get-started/actions/type', 'get-started/actions/wait' ] } From 507bc939236c0294da6665fa49a5949153d7a4da Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Wed, 23 Apr 2025 19:30:24 -0700 Subject: [PATCH 24/31] Update dependencies in package.json - Bump version of doc-detective-common to ^3.0.1 - Update dotenv to ^16.5.0 - Upgrade react and react-dom to ^19.1.0 --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index ed73fc75..3d8fe559 100644 --- a/package.json +++ b/package.json @@ -28,15 +28,15 @@ "@mui/icons-material": "^6.4.3", "@mui/material": "^6.4.3", "clsx": "^2.1.1", - "doc-detective-common": "^3.0.0", - "dotenv": "^16.4.7", + "doc-detective-common": "^3.0.1", + "dotenv": "^16.5.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", "posthog-docusaurus": "^2.0.4", "prism-react-renderer": "^2.4.1", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", "react-markdown": "^9.0.3", "stream-http": "^3.2.0", "yaml": "^2.7.1" From f367597e31f19196a1510e6dcc6e9a4c4bd408c7 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Thu, 24 Apr 2025 09:24:07 -0700 Subject: [PATCH 25/31] Refactor test steps and action definitions for clarity - Update action keys in the test JSON structure for consistency. - Modify descriptions to better reflect the actions being performed. - Change output format for the test results to enhance readability. --- docs/get-started/create-your-first-test.md | 88 +++++++++------------- 1 file changed, 36 insertions(+), 52 deletions(-) diff --git a/docs/get-started/create-your-first-test.md b/docs/get-started/create-your-first-test.md index 5ede0fc3..ca25425a 100644 --- a/docs/get-started/create-your-first-test.md +++ b/docs/get-started/create-your-first-test.md @@ -45,27 +45,20 @@ To create your first test, follow these steps: { "steps": [ { - "action": "goTo", "description": "Go to the specified URL", - "url": "https://example.com" + "goTo": "https://example.com" }, { - "action": "find", "description": "Verify the presence of the main heading", - "selector": "h1", - "matchText": "Example Domain" + "find": "Example Domain" }, { - "action": "find", "description": "Verify that the 'More information...' link is present and working", - "selector": "a", - "matchText": "More information...", - "click": true + "click": "More information..." }, { - "action": "saveScreenshot", "description": "Capture a screenshot of the resulting page", - "path": "example.png" + "screenshot": "example.png" } ] } @@ -77,7 +70,8 @@ To create your first test, follow these steps: - [`goTo`](/docs/get-started/actions/goTo.md): Navigates to the specified URL, https://example.com, to start the test flow. - [`find`](/docs/get-started/actions/find.md): Locates elements on the page using CSS selectors such as HTML tags like `h1` or `a`, and validates their presence and text content. - - [`saveScreenshot`](/docs/get-started/actions/saveScreenshot.md): Captures a screenshot of the current page and saves it to the specified path. + - [`click`](/docs/get-started/actions/click.md): Clicks on the specified element, in this case, the `More information...` link. + - [`screenshot`](/docs/get-started/actions/screenshot.md): Captures a screenshot of the current page and saves it to the specified path. 4. Save the file. @@ -93,88 +87,78 @@ To create your first test, follow these steps: After running the test, you should see the results in your terminal, which Doc Detective saves to a new file named `testResults-UNIQUE_ID.json`: -```text title="testResults-UNIQUE_ID.json" +```json title="testResults-UNIQUE_ID.json" { "summary": { "specs": { - "pass": 1, // Number of test specifications that passed - "fail": 0, // Number of test specifications that failed + "pass": 1, // Number of test specifications that passed + "fail": 0, // Number of test specifications that failed "warning": 0, "skipped": 0 }, "tests": { - "pass": 1, // Number of tests that passed - "fail": 0, // Number of tests that failed + "pass": 1, // Number of tests that passed + "fail": 0, // Number of tests that failed "warning": 0, "skipped": 0 }, "contexts": { - "pass": 1, // Number of contexts that passed - "fail": 0, // Number of contexts that failed + "pass": 1, // Number of contexts that passed + "fail": 0, // Number of contexts that failed "warning": 0, "skipped": 0 }, "steps": { - "pass": 4, // Number of individual steps that passed - "fail": 0, // Number of individual steps that failed + "pass": 4, // Number of individual steps that passed + "fail": 0, // Number of individual steps that failed "warning": 0, "skipped": 0 } }, "specs": [ { - "result": "PASS", "tests": [ { "result": "PASS", "contexts": [ { "result": "PASS", - "app": "chrome", - "path": "/opt/homebrew/lib/node_modules/doc-detective/node_modules/doc-detective-core/browser-snapshots/chrome/mac_arm-128.0.6613.119/chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing", - "platform": "mac", + "platform": "linux", + "browser": { + "name": "firefox", + "version": "nightly_136.0a1", + "path": "/home/hawkeyexl/Workspaces/doc-detective-core/browser-snapshots/firefox/linux-nightly_136.0a1/firefox/firefox" + }, "steps": [ { "result": "PASS", "resultDescription": "Opened URL.", - "action": "goTo", - "url": "https://example.com", - "id": "89889930-25b1-460b-a57f-68188c7be3d7" + "description": "Go to the specified URL", + "goTo": { + "url": "https://example.com" + }, + "stepId": "b09d9c07-2fb0-4fc9-92a4-b4cabdb5c3cd" }, { "result": "PASS", - "resultDescription": "Found an element matching selector. Matched text.", - "action": "find", + "resultDescription": "Found an element matching selector. Found element by text.", "description": "Verify the presence of the main heading", - "selector": "h1", - "matchText": "Example Domain", - "timeout": 5000, - "moveTo": false, - "click": false, - "setVariables": [], - "id": "f5bc70a7-82cf-4b60-adac-b51a77c1d0c2" + "find": "Example Domain", + "stepId": "94dd9246-e612-43be-829e-607a191550e8" }, { "result": "PASS", - "resultDescription": "Found an element matching selector. Matched text. Clicked element.", - "action": "find", - "description": "Verify that the 'More information...' link is present and is working", - "selector": "a", - "matchText": "More information...", - "click": true, - "timeout": 5000, - "moveTo": false, - "setVariables": [], - "id": "1c9b165b-416f-4c66-b7f5-81e44f5590f4" + "resultDescription": "Clicked element. Found element by text. Clicked element.", + "description": "Verify that the 'More information...' link is present and working", + "click": "More information...", + "stepId": "d5851502-807f-4cb9-981c-338201278f29" }, { "result": "PASS", "resultDescription": "Saved screenshot.", - "action": "saveScreenshot", - "path": "/Users/doc-detective-user/path/to/your/project/example.png", - "maxVariation": 5, - "overwrite": "false", - "id": "c2bb9f2f-f9d7-4e8c-bc53-4a1b557c2a3c" + "description": "Capture a screenshot of the resulting page", + "screenshot": "example.png", + "stepId": "5698d891-e220-4e88-8b96-8c5eb8c1ce5f" } ] } From bc838fbf99da088ebaa74c6c16a80b310b10a240 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Thu, 24 Apr 2025 10:13:27 -0700 Subject: [PATCH 26/31] Update click action documentation for clarity - Change "Boolean Shorthand" to "String Shorthand" for consistency. - Clarify the description of the click action's properties. - Update examples to reflect correct usage of the click action. --- docs/get-started/actions/click.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/get-started/actions/click.md b/docs/get-started/actions/click.md index 611bd9ab..e46077d6 100644 --- a/docs/get-started/actions/click.md +++ b/docs/get-started/actions/click.md @@ -12,21 +12,21 @@ description: Click or tap an element on the page. The `click` action allows you to click or tap an element on the page. You can specify which mouse button to use and target elements using text or selectors. The `click` action works in several ways: -- **Boolean Shorthand:** Set to `true` to perform a standard left click on the active element. -- **String Shorthand:** Specify the button type directly as `"left"`, `"right"`, or `"middle"`. + +- **String Shorthand:** The display text or selector of the element to find and click. - **Object Format:** Use an object with detailed properties for more control over the click action. If you need to find an element before clicking it, consider using the [`find`](/docs/get-started/actions/find) action, which lets you locate elements and optionally click them in a single step. -**Note:** If you use the `click` action without the `find` action, it will click the active element or the element at the current cursor position. +**Note:** If you use the `click` action without specifying a target (using element text or selector), it will click the active element or the element at the current cursor position. ## Properties When using the object format, you can specify: -- `button`: (Optional) Which mouse button to use. Can be `"left"`, `"right"`, or `"middle"`. Default is `"left"`. -- `selector`: (Optional) CSS or XPath selector of the element to click. If combined with `elementText`, the element must match both. -- `elementText`: (Optional) Display text of the element to click. If combined with `selector`, the element must match both. +- `button`: (Optional) Kind of click to perform. Can be `"left"`, `"right"`, or `"middle"`. Default is `"left"`. +- `selector`: (Optional) CSS or XPath selector of the element to click. If combined with `elementText`, the element must match both the text and the selector. +- `elementText`: (Optional) Display text of the element to click. If combined with `selector`, the element must match both the text and the selector. > For comprehensive options, see the full [`click`](/docs/references/schemas/click) reference. @@ -34,7 +34,7 @@ When using the object format, you can specify: Here are a few ways you might use the `click` action: -### Simple left click (boolean shorthand) +### Click by element text (string shorthand) ```json { @@ -42,8 +42,8 @@ Here are a few ways you might use the `click` action: { "steps": [ { - "description": "Click the currently focused element", - "click": true + "description": "Click on an element with text 'Submit'", + "click": "Submit" } ] } @@ -51,7 +51,7 @@ Here are a few ways you might use the `click` action: } ``` -### Specify button type (string shorthand) +### Click by selector (string shorthand) ```json { @@ -59,8 +59,8 @@ Here are a few ways you might use the `click` action: { "steps": [ { - "description": "Right-click the currently focused element", - "click": "right" + "description": "Click on an element matching the CSS selector", + "click": "#submit-button" } ] } @@ -78,8 +78,8 @@ Here are a few ways you might use the `click` action: { "description": "Left-click on a button with specific text", "click": { - "button": "left", - "elementText": "Submit" + "elementText": "Submit", + "button": "left" } } ] From ad7e404c418fc69cc86d3da6d48f1aad72dc031b Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Thu, 24 Apr 2025 11:01:28 -0700 Subject: [PATCH 27/31] Update package dependencies - Bump version of doc-detective-common to 3.0.2 - Update dotenv to version 16.5.0 - Upgrade react and react-dom to version 19.1.0 - Update scheduler to version 0.26.0 --- package-lock.json | 42 +++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2358aa4a..0cc48a06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,15 +17,15 @@ "@mui/icons-material": "^6.4.3", "@mui/material": "^6.4.3", "clsx": "^2.1.1", - "doc-detective-common": "^3.0.0", - "dotenv": "^16.4.7", + "doc-detective-common": "^3.0.2", + "dotenv": "^16.5.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", "posthog-docusaurus": "^2.0.4", "prism-react-renderer": "^2.4.1", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", "react-markdown": "^9.0.3", "stream-http": "^3.2.0", "yaml": "^2.7.1" @@ -10162,9 +10162,9 @@ } }, "node_modules/doc-detective-common": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doc-detective-common/-/doc-detective-common-3.0.0.tgz", - "integrity": "sha512-mtRAV/Ysc+JnjqFQZv05eJIQj0MWQtZZQHPdwioXL1PEyl8O0GSSsHsh5iuQk5Nnnf7JYbP3AYzSnYyB93a9xA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/doc-detective-common/-/doc-detective-common-3.0.2.tgz", + "integrity": "sha512-Gh5EAwwuG7aN9FBKUt1pj4zUuWPBCCz7SL3McjeWYjtvmdGbQOg4XHAESK87INC4tZLIHm+7snymXv9VkP8QTw==", "license": "AGPL-3.0-only", "dependencies": { "@apidevtools/json-schema-ref-parser": "^12.0.1", @@ -10340,9 +10340,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -19113,9 +19113,9 @@ } }, "node_modules/react": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", - "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -19351,15 +19351,15 @@ } }, "node_modules/react-dom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", - "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", "dependencies": { - "scheduler": "^0.25.0" + "scheduler": "^0.26.0" }, "peerDependencies": { - "react": "^19.0.0" + "react": "^19.1.0" } }, "node_modules/react-error-overlay": { @@ -20289,9 +20289,9 @@ "license": "ISC" }, "node_modules/scheduler": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", - "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", "license": "MIT" }, "node_modules/schema-utils": { diff --git a/package.json b/package.json index 3d8fe559..ecc54ac3 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@mui/icons-material": "^6.4.3", "@mui/material": "^6.4.3", "clsx": "^2.1.1", - "doc-detective-common": "^3.0.1", + "doc-detective-common": "^3.0.2", "dotenv": "^16.5.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", From 038a605cb83f1b76767f7cc6d239bfc9850b8efe Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Thu, 24 Apr 2025 11:02:07 -0700 Subject: [PATCH 28/31] Update click field description in step schema - Clarify the options for the click field to include references to detailed schemas. --- docs/references/schemas/step.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/references/schemas/step.md b/docs/references/schemas/step.md index 00ec1bb4..26eff3e1 100644 --- a/docs/references/schemas/step.md +++ b/docs/references/schemas/step.md @@ -12,7 +12,7 @@ description | string | Optional. Description of the step. | outputs | object | Optional. Outputs from step processes and user-defined expressions. Use the `outputs` object to reference outputs in subsequent steps. If a user-defined output matches the key for a step-defined output, the user-defined output takes precedence. | ``{}`` variables | object | Optional. Environment variables to set from user-defined expressions. | ``{}`` checkLink | One of
- string
- object | Optional. No description provided. | -click | One of
- string
- object
- boolean | Optional. Click or tap an element. | +click | One of
- string([Find element (simple)](/docs/references/schemas/Find element (simple)))
- object([Click element (detailed)](/docs/references/schemas/Click element (detailed)))
- boolean | Optional. Click or tap an element. | find | One of
- string([Find element (simple)](/docs/references/schemas/Find element (simple)))
- object([Find element (detailed)](/docs/references/schemas/Find element (detailed))) | Optional. Find an element based on display text or a selector, then optionally interact with it. | goTo | One of
- string
- object | Optional. No description provided. | httpRequest | One of
- string([URL](/docs/references/schemas/URL))
- object | Optional. Perform a generic HTTP request, for example to an API. | From c4d9fae7aafcae56c4da84c9dae1197cdaa7bef0 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Thu, 24 Apr 2025 11:02:35 -0700 Subject: [PATCH 29/31] Set version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0cc48a06..5b022f16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doc-detective-docs", - "version": "2.0.7", + "version": "3.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doc-detective-docs", - "version": "2.0.7", + "version": "3.0.0", "dependencies": { "@docusaurus/core": "3.7.0", "@docusaurus/preset-classic": "3.7.0", diff --git a/package.json b/package.json index ecc54ac3..760465c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doc-detective-docs", - "version": "2.0.7", + "version": "3.0.0", "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", From ece676fe5570b43f8df0958f75fc9343d0c065e1 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Thu, 24 Apr 2025 11:04:17 -0700 Subject: [PATCH 30/31] Commented out the reference and app builder nav elements --- docusaurus.config.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 3b6c6c1c..96227339 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -74,13 +74,13 @@ const config: Config = { position: "left", label: "Get started", }, - { - type: "docSidebar", - sidebarId: "referencesSidebar", - position: "left", - label: "References", - }, - { to: "/app", label: "Action Builder (beta)", position: "left" }, + // { + // type: "docSidebar", + // sidebarId: "referencesSidebar", + // position: "left", + // label: "References", + // }, + // { to: "/app", label: "Action Builder (beta)", position: "left" }, // {to: '/blog', label: 'Blog', position: 'left'}, { to: "/support", label: "Support ❤️", position: "right" }, { From 5833d3a413e772a3ec6b16836d47e742dd268005 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Thu, 24 Apr 2025 11:12:19 -0700 Subject: [PATCH 31/31] - Update references in documentation for `type` action to point to the correct schema. - Modify `fileTypes` description in config schema for clarity. - Adjust `httpRequest` type definition for consistency. - Add new `type` schema documentation with detailed examples. --- docs/get-started/actions/find.md | 2 +- docs/get-started/actions/type.md | 2 +- docs/references/schemas/config.md | 2 +- docs/references/schemas/step.md | 2 +- docs/references/schemas/{typeKeys.md => type.md} | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename docs/references/schemas/{typeKeys.md => type.md} (98%) diff --git a/docs/get-started/actions/find.md b/docs/get-started/actions/find.md index 269ec122..1b02d5cf 100644 --- a/docs/get-started/actions/find.md +++ b/docs/get-started/actions/find.md @@ -23,7 +23,7 @@ You can specify the target element directly using a string (for simple text or s - `timeout`: (Optional) Maximum duration in milliseconds to wait for the element to exist (default: 5000). - `moveTo`: (Optional) Move the cursor to the element. If the element isn't visible, it's scrolled into view (default: `true`). - `click`: (Optional) Click the element after finding it. Can be `true` (for a default left click), `"left"`, `"right"`, `"middle"`, or an object like `{ "button": "right" }`. - - `type`: (Optional) Type keys after finding the element. Requires the element to be made active first (e.g., by using `click: true`). Accepts a string or an object like `{ "keys": "my text", "inputDelay": 100 }`. See [`typeKeys`](/docs/references/schemas/typeKeys) for details. + - `type`: (Optional) Type keys after finding the element. Requires the element to be made active first (e.g., by using `click: true`). Accepts a string or an object like `{ "keys": "my text", "inputDelay": 100 }`. See [`type`](type) for details. **Setting Variables:** To capture a found element's attributes into variables for later steps, use the step-level `variables` object. You can assign values based on the element using expressions like `$$element.text`. diff --git a/docs/get-started/actions/type.md b/docs/get-started/actions/type.md index 41807762..6b916374 100644 --- a/docs/get-started/actions/type.md +++ b/docs/get-started/actions/type.md @@ -19,7 +19,7 @@ You can specify the keys to type in several ways: - `keys`: (Required) A string or an array of strings representing the keys to type. - `inputDelay`: (Optional) Delay in milliseconds between each key press. Useful for making recordings more legible. -> For comprehensive options, see the [`type`](/docs/references/schemas/typeKeys) reference. +> For comprehensive options, see the [`type`](/docs/references/schemas/type) reference. ## Special keys diff --git a/docs/references/schemas/config.md b/docs/references/schemas/config.md index 257711d7..6056f23e 100644 --- a/docs/references/schemas/config.md +++ b/docs/references/schemas/config.md @@ -19,7 +19,7 @@ afterAll | One of
- string
- array of string | Optional. Path detectSteps | boolean | Optional. Whether or not to detect steps in input files based on defined markup. | `true` logLevel | string | Optional. Amount of detail to output when performing an operation.

Accepted values: `silent`, `error`, `warning`, `info`, `debug` | `info` runOn | array of object([context](/docs/references/schemas/context)) | Optional. Contexts to run the test in. Overrides contexts defined at the config and spec levels. | -fileTypes | array of
one of:
- string
- object([Custom](/docs/references/schemas/Custom))
- object([Executable](/docs/references/schemas/Executable)) | Optional. Configuration for file types and their markup detection. | [] +fileTypes | array of
one of:
- string
- object | Optional. Configuration for file types and their markup detection. | [] integrations | object | Optional. Options for connecting to external services. | integrations.openApi | array of unknown | Optional. No description provided. | telemetry | object | Optional. Options around sending telemetry for Doc Detective usage. | ``{"send":true}`` diff --git a/docs/references/schemas/step.md b/docs/references/schemas/step.md index 26eff3e1..4d186043 100644 --- a/docs/references/schemas/step.md +++ b/docs/references/schemas/step.md @@ -15,7 +15,7 @@ checkLink | One of
- string
- object | Optional. No descripti click | One of
- string([Find element (simple)](/docs/references/schemas/Find element (simple)))
- object([Click element (detailed)](/docs/references/schemas/Click element (detailed)))
- boolean | Optional. Click or tap an element. | find | One of
- string([Find element (simple)](/docs/references/schemas/Find element (simple)))
- object([Find element (detailed)](/docs/references/schemas/Find element (detailed))) | Optional. Find an element based on display text or a selector, then optionally interact with it. | goTo | One of
- string
- object | Optional. No description provided. | -httpRequest | One of
- string([URL](/docs/references/schemas/URL))
- object | Optional. Perform a generic HTTP request, for example to an API. | +httpRequest | One of
- string(URL)
- object | Optional. Perform a generic HTTP request, for example to an API. | runShell | One of
- string
- object | Optional. Perform a native shell command. | runCode | object | Optional. Assemble and run code. | runCode.language | string | Optional. Language of the code to run.

Accepted values: `python`, `bash`, `javascript` | diff --git a/docs/references/schemas/typeKeys.md b/docs/references/schemas/type.md similarity index 98% rename from docs/references/schemas/typeKeys.md rename to docs/references/schemas/type.md index 3129d39c..50bb8872 100644 --- a/docs/references/schemas/typeKeys.md +++ b/docs/references/schemas/type.md @@ -1,5 +1,5 @@ -# typeKeys +# type 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$`.