cumulocity-cypress
Version:
Cypress commands for Cumulocity IoT
4,609 lines • 139 kB
JavaScript
'use strict';
var _ = require('lodash');
var semver = require('semver');
var Ajv = require('ajv');
var addFormats = require('ajv-formats');
require('ajv/lib/refs/json-schema-draft-06.json');
var datefns = require('date-fns');
var util = require('./util-C7wrzo9A.js');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var semver__namespace = /*#__PURE__*/_interopNamespaceDefault(semver);
var datefns__namespace = /*#__PURE__*/_interopNamespaceDefault(datefns);
var $schema = "http://json-schema.org/draft-07/schema#";
var additionalProperties = false;
var definitions = {
Action: {
additionalProperties: false,
properties: {
blur: {
anyOf: [
{
additionalProperties: false,
properties: {
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
"const": true,
type: "boolean"
},
{
type: "string"
}
],
description: "A blur action triggers a blur event on the selected DOM element to remove focus."
},
click: {
anyOf: [
{
additionalProperties: false,
properties: {
force: {
"default": false,
description: "If true, the click event is triggered even if the element is not visible. The default is false.",
type: "boolean"
},
multiple: {
"default": false,
description: "If true, the click event is triggered on all matching elements. The default is false.",
type: "boolean"
},
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
},
force: {
"default": false,
description: "If true, the click event is triggered even if the element is not visible. The default is false.",
type: "boolean"
},
multiple: {
"default": false,
description: "If true, the click event is triggered on all matching elements. The default is false.",
type: "boolean"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
force: {
"default": false,
description: "If true, the click event is triggered even if the element is not visible. The default is false.",
type: "boolean"
},
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
},
multiple: {
"default": false,
description: "If true, the click event is triggered on all matching elements. The default is false.",
type: "boolean"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
force: {
"default": false,
description: "If true, the click event is triggered even if the element is not visible. The default is false.",
type: "boolean"
},
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
},
multiple: {
"default": false,
description: "If true, the click event is triggered on all matching elements. The default is false.",
type: "boolean"
}
},
type: "object"
},
{
type: "string"
}
],
description: "A click action triggers a click event on the selected DOM element."
},
fileUpload: {
anyOf: [
{
additionalProperties: false,
properties: {
encoding: {
description: "The encoding of the file. If not provided, the encoding is determined automatically. Default is 'utf8' or 'binary' depending of file extension.",
"enum": [
"binary",
"utf-8",
"utf8"
],
examples: [
[
"binary",
"utf8"
]
],
type: "string"
},
file: {
description: "The path to the file to upload. Resolve the file path relative to the current working directory. Currently, only a single file of types .json, .txt, .csv, .png, .jpg, .jpeg, .gif can be uploaded. If file does not have required extension, overwrite extension in the fileName property.",
type: "string"
},
fileName: {
description: "The name of the file to use when uploading including file extension. If not provided, the file name is determined from the file path.",
examples: [
"file.txt"
],
type: "string"
},
force: {
"default": false,
description: "If true, the file is uploaded even if the element is not visible. The default is false.",
type: "boolean"
},
mimeType: {
description: "The MIME type of the file. If not provided, the MIME type is determined automatically.",
examples: [
"application/json",
"text/csv",
"image/png"
],
type: "string"
},
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
},
subjectType: {
"default": "input",
description: "The type of the file input element. The default is 'input'.",
"enum": [
"drag-n-drop",
"input"
],
type: "string"
}
},
required: [
"file",
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
},
encoding: {
description: "The encoding of the file. If not provided, the encoding is determined automatically. Default is 'utf8' or 'binary' depending of file extension.",
"enum": [
"binary",
"utf-8",
"utf8"
],
examples: [
[
"binary",
"utf8"
]
],
type: "string"
},
file: {
description: "The path to the file to upload. Resolve the file path relative to the current working directory. Currently, only a single file of types .json, .txt, .csv, .png, .jpg, .jpeg, .gif can be uploaded. If file does not have required extension, overwrite extension in the fileName property.",
type: "string"
},
fileName: {
description: "The name of the file to use when uploading including file extension. If not provided, the file name is determined from the file path.",
examples: [
"file.txt"
],
type: "string"
},
force: {
"default": false,
description: "If true, the file is uploaded even if the element is not visible. The default is false.",
type: "boolean"
},
mimeType: {
description: "The MIME type of the file. If not provided, the MIME type is determined automatically.",
examples: [
"application/json",
"text/csv",
"image/png"
],
type: "string"
},
subjectType: {
"default": "input",
description: "The type of the file input element. The default is 'input'.",
"enum": [
"drag-n-drop",
"input"
],
type: "string"
}
},
required: [
"file"
],
type: "object"
},
{
additionalProperties: false,
properties: {
encoding: {
description: "The encoding of the file. If not provided, the encoding is determined automatically. Default is 'utf8' or 'binary' depending of file extension.",
"enum": [
"binary",
"utf-8",
"utf8"
],
examples: [
[
"binary",
"utf8"
]
],
type: "string"
},
file: {
description: "The path to the file to upload. Resolve the file path relative to the current working directory. Currently, only a single file of types .json, .txt, .csv, .png, .jpg, .jpeg, .gif can be uploaded. If file does not have required extension, overwrite extension in the fileName property.",
type: "string"
},
fileName: {
description: "The name of the file to use when uploading including file extension. If not provided, the file name is determined from the file path.",
examples: [
"file.txt"
],
type: "string"
},
force: {
"default": false,
description: "If true, the file is uploaded even if the element is not visible. The default is false.",
type: "boolean"
},
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
},
mimeType: {
description: "The MIME type of the file. If not provided, the MIME type is determined automatically.",
examples: [
"application/json",
"text/csv",
"image/png"
],
type: "string"
},
subjectType: {
"default": "input",
description: "The type of the file input element. The default is 'input'.",
"enum": [
"drag-n-drop",
"input"
],
type: "string"
}
},
required: [
"file"
],
type: "object"
},
{
additionalProperties: false,
properties: {
encoding: {
description: "The encoding of the file. If not provided, the encoding is determined automatically. Default is 'utf8' or 'binary' depending of file extension.",
"enum": [
"binary",
"utf-8",
"utf8"
],
examples: [
[
"binary",
"utf8"
]
],
type: "string"
},
file: {
description: "The path to the file to upload. Resolve the file path relative to the current working directory. Currently, only a single file of types .json, .txt, .csv, .png, .jpg, .jpeg, .gif can be uploaded. If file does not have required extension, overwrite extension in the fileName property.",
type: "string"
},
fileName: {
description: "The name of the file to use when uploading including file extension. If not provided, the file name is determined from the file path.",
examples: [
"file.txt"
],
type: "string"
},
force: {
"default": false,
description: "If true, the file is uploaded even if the element is not visible. The default is false.",
type: "boolean"
},
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
},
mimeType: {
description: "The MIME type of the file. If not provided, the MIME type is determined automatically.",
examples: [
"application/json",
"text/csv",
"image/png"
],
type: "string"
},
subjectType: {
"default": "input",
description: "The type of the file input element. The default is 'input'.",
"enum": [
"drag-n-drop",
"input"
],
type: "string"
}
},
required: [
"file"
],
type: "object"
},
{
type: "string"
}
],
description: "Use the file upload action to upload a file using the file input element. Currently supported file types are .json, .txt, .csv, .png, .jpg, .jpeg, .gif."
},
focus: {
anyOf: [
{
additionalProperties: false,
properties: {
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "A focus action triggers a focus event on the selected DOM element."
},
highlight: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
additionalProperties: false,
properties: {
border: {
description: "The border style. Use any valid CSS border style. If provided an object, keys override the default border style.",
examples: [
"1px solid red"
]
},
clear: {
"default": false,
description: "If true, existing highlights will be cleared before highlighting. The default is false.",
type: "boolean"
},
detached: {
"default": false,
description: "If true, the highlight styles are applied to a detached <div> element instead of the target element. This is done automatically for elements with rounded corners or disabled elements to avoid visual issues. Use detached:true to force detached highlights.",
type: "boolean"
},
height: {
description: "Overwrite the height of the highlighted element. If smaller than 1, the value is used as percentage of the element height.",
type: "number"
},
multiple: {
"default": false,
description: "If true, the highlight is applied to all elements in the selection. The default is false.",
type: "boolean"
},
offset: {
description: "The outline offset. The default is -2px.",
type: "string"
},
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
},
styles: {
description: "The CSS styles to apply to the DOM element. Use any valid CSS styles.",
examples: [
[
"background-color: yellow",
"outline: dashed",
"outline-offset: +3px"
]
]
},
width: {
description: "Overwrite the width of the highlighted element. If smaller than 1, the value is used as percentage of the element width.",
type: "number"
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
border: {
description: "The border style. Use any valid CSS border style. If provided an object, keys override the default border style.",
examples: [
"1px solid red"
]
},
clear: {
"default": false,
description: "If true, existing highlights will be cleared before highlighting. The default is false.",
type: "boolean"
},
"data-cy": {
type: "string"
},
detached: {
"default": false,
description: "If true, the highlight styles are applied to a detached <div> element instead of the target element. This is done automatically for elements with rounded corners or disabled elements to avoid visual issues. Use detached:true to force detached highlights.",
type: "boolean"
},
height: {
description: "Overwrite the height of the highlighted element. If smaller than 1, the value is used as percentage of the element height.",
type: "number"
},
multiple: {
"default": false,
description: "If true, the highlight is applied to all elements in the selection. The default is false.",
type: "boolean"
},
offset: {
description: "The outline offset. The default is -2px.",
type: "string"
},
styles: {
description: "The CSS styles to apply to the DOM element. Use any valid CSS styles.",
examples: [
[
"background-color: yellow",
"outline: dashed",
"outline-offset: +3px"
]
]
},
width: {
description: "Overwrite the width of the highlighted element. If smaller than 1, the value is used as percentage of the element width.",
type: "number"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
border: {
description: "The border style. Use any valid CSS border style. If provided an object, keys override the default border style.",
examples: [
"1px solid red"
]
},
clear: {
"default": false,
description: "If true, existing highlights will be cleared before highlighting. The default is false.",
type: "boolean"
},
detached: {
"default": false,
description: "If true, the highlight styles are applied to a detached <div> element instead of the target element. This is done automatically for elements with rounded corners or disabled elements to avoid visual issues. Use detached:true to force detached highlights.",
type: "boolean"
},
height: {
description: "Overwrite the height of the highlighted element. If smaller than 1, the value is used as percentage of the element height.",
type: "number"
},
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
},
multiple: {
"default": false,
description: "If true, the highlight is applied to all elements in the selection. The default is false.",
type: "boolean"
},
offset: {
description: "The outline offset. The default is -2px.",
type: "string"
},
styles: {
description: "The CSS styles to apply to the DOM element. Use any valid CSS styles.",
examples: [
[
"background-color: yellow",
"outline: dashed",
"outline-offset: +3px"
]
]
},
width: {
description: "Overwrite the width of the highlighted element. If smaller than 1, the value is used as percentage of the element width.",
type: "number"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
border: {
description: "The border style. Use any valid CSS border style. If provided an object, keys override the default border style.",
examples: [
"1px solid red"
]
},
clear: {
"default": false,
description: "If true, existing highlights will be cleared before highlighting. The default is false.",
type: "boolean"
},
detached: {
"default": false,
description: "If true, the highlight styles are applied to a detached <div> element instead of the target element. This is done automatically for elements with rounded corners or disabled elements to avoid visual issues. Use detached:true to force detached highlights.",
type: "boolean"
},
height: {
description: "Overwrite the height of the highlighted element. If smaller than 1, the value is used as percentage of the element height.",
type: "number"
},
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
},
multiple: {
"default": false,
description: "If true, the highlight is applied to all elements in the selection. The default is false.",
type: "boolean"
},
offset: {
description: "The outline offset. The default is -2px.",
type: "string"
},
styles: {
description: "The CSS styles to apply to the DOM element. Use any valid CSS styles.",
examples: [
[
"background-color: yellow",
"outline: dashed",
"outline-offset: +3px"
]
]
},
width: {
description: "Overwrite the width of the highlighted element. If smaller than 1, the value is used as percentage of the element width.",
type: "number"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
clear: {
"const": true,
type: "boolean"
}
},
required: [
"clear"
],
type: "object"
},
{
items: {
anyOf: [
{
additionalProperties: false,
properties: {
border: {
description: "The border style. Use any valid CSS border style. If provided an object, keys override the default border style.",
examples: [
"1px solid red"
]
},
clear: {
"default": false,
description: "If true, existing highlights will be cleared before highlighting. The default is false.",
type: "boolean"
},
detached: {
"default": false,
description: "If true, the highlight styles are applied to a detached <div> element instead of the target element. This is done automatically for elements with rounded corners or disabled elements to avoid visual issues. Use detached:true to force detached highlights.",
type: "boolean"
},
height: {
description: "Overwrite the height of the highlighted element. If smaller than 1, the value is used as percentage of the element height.",
type: "number"
},
multiple: {
"default": false,
description: "If true, the highlight is applied to all elements in the selection. The default is false.",
type: "boolean"
},
offset: {
description: "The outline offset. The default is -2px.",
type: "string"
},
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
},
styles: {
description: "The CSS styles to apply to the DOM element. Use any valid CSS styles.",
examples: [
[
"background-color: yellow",
"outline: dashed",
"outline-offset: +3px"
]
]
},
width: {
description: "Overwrite the width of the highlighted element. If smaller than 1, the value is used as percentage of the element width.",
type: "number"
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
border: {
description: "The border style. Use any valid CSS border style. If provided an object, keys override the default border style.",
examples: [
"1px solid red"
]
},
clear: {
"default": false,
description: "If true, existing highlights will be cleared before highlighting. The default is false.",
type: "boolean"
},
"data-cy": {
type: "string"
},
detached: {
"default": false,
description: "If true, the highlight styles are applied to a detached <div> element instead of the target element. This is done automatically for elements with rounded corners or disabled elements to avoid visual issues. Use detached:true to force detached highlights.",
type: "boolean"
},
height: {
description: "Overwrite the height of the highlighted element. If smaller than 1, the value is used as percentage of the element height.",
type: "number"
},
multiple: {
"default": false,
description: "If true, the highlight is applied to all elements in the selection. The default is false.",
type: "boolean"
},
offset: {
description: "The outline offset. The default is -2px.",
type: "string"
},
styles: {
description: "The CSS styles to apply to the DOM element. Use any valid CSS styles.",
examples: [
[
"background-color: yellow",
"outline: dashed",
"outline-offset: +3px"
]
]
},
width: {
description: "Overwrite the width of the highlighted element. If smaller than 1, the value is used as percentage of the element width.",
type: "number"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
border: {
description: "The border style. Use any valid CSS border style. If provided an object, keys override the default border style.",
examples: [
"1px solid red"
]
},
clear: {
"default": false,
description: "If true, existing highlights will be cleared before highlighting. The default is false.",
type: "boolean"
},
detached: {
"default": false,
description: "If true, the highlight styles are applied to a detached <div> element instead of the target element. This is done automatically for elements with rounded corners or disabled elements to avoid visual issues. Use detached:true to force detached highlights.",
type: "boolean"
},
height: {
description: "Overwrite the height of the highlighted element. If smaller than 1, the value is used as percentage of the element height.",
type: "number"
},
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
},
multiple: {
"default": false,
description: "If true, the highlight is applied to all elements in the selection. The default is false.",
type: "boolean"
},
offset: {
description: "The outline offset. The default is -2px.",
type: "string"
},
styles: {
description: "The CSS styles to apply to the DOM element. Use any valid CSS styles.",
examples: [
[
"background-color: yellow",
"outline: dashed",
"outline-offset: +3px"
]
]
},
width: {
description: "Overwrite the width of the highlighted element. If smaller than 1, the value is used as percentage of the element width.",
type: "number"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
border: {
description: "The border style. Use any valid CSS border style. If provided an object, keys override the default border style.",
examples: [
"1px solid red"
]
},
clear: {
"default": false,
description: "If true, existing highlights will be cleared before highlighting. The default is false.",
type: "boolean"
},
detached: {
"default": false,
description: "If true, the highlight styles are applied to a detached <div> element instead of the target element. This is done automatically for elements with rounded corners or disabled elements to avoid visual issues. Use detached:true to force detached highlights.",
type: "boolean"
},
height: {
description: "Overwrite the height of the highlighted element. If smaller than 1, the value is used as percentage of the element height.",
type: "number"
},
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
},
multiple: {
"default": false,
description: "If true, the highlight is applied to all elements in the selection. The default is false.",
type: "boolean"
},
offset: {
description: "The outline offset. The default is -2px.",
type: "string"
},
styles: {
description: "The CSS styles to apply to the DOM element. Use any valid CSS styles.",
examples: [
[
"background-color: yellow",
"outline: dashed",
"outline-offset: +3px"
]
]
},
width: {
description: "Overwrite the width of the highlighted element. If smaller than 1, the value is used as percentage of the element width.",
type: "number"
}
},
type: "object"
},
{
type: "string"
}
]
},
type: "array"
},
{
type: "string"
}
],
description: "Use highlight action to visually highlight a selected DOM element in the screenshot. By default, the element is highlighted with an orange border. Use any valid CSS styles to highlight the element.\nTo clear existing highlights, set the clear property to true."
},
screenshot: {
anyOf: [
{
additionalProperties: false,
properties: {
clip: {
$ref: "#/definitions/ScreenshotClipArea",
description: "The clip area within the screenshot image. The clip area is defined by the top-left corner (x, y) and the width and height of the clip area."
},
padding: {
anyOf: [
{
items: [
{
type: "number"
},
{
type: "number"
}
],
maxItems: 2,
minItems: 2,
type: "array"
},
{
items: [
{
type: "number"
}
],
maxItems: 1,
minItems: 1,
type: "array"
},
{
items: [
{
type: "number"
},
{
type: "number"
},
{
type: "number"
}
],
maxItems: 3,
minItems: 3,
type: "array"
},
{
items: [
{
type: "number"
},
{
type: "number"
},
{
type: "number"
},
{
type: "number"
}
],
maxItems: 4,
minItems: 4,
type: "array"
},
{
type: "number"
}
],
description: "The padding applied to the screenshots of elements in px. If an array of numbers is provided, the padding is applied as defined by CSS shorthand property."
},
path: {
description: "The path to store the screenshot. This is the relative path used within the screenshot folder.",
type: "string"
},
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
clip: {
$ref: "#/definitions/ScreenshotClipArea",
description: "The clip area within the screenshot image. The clip area is defined by the top-left corner (x, y) and the width and height of the clip area."
},
"data-cy": {
type: "string"
},
padding: {
anyOf: [
{
items: [
{
type: "number"
},
{
type: "number"
}
],
maxItems: 2,
minItems: 2,
type: "array"
},
{
items: [
{
type: "number"
}
],
maxItems: 1,
minItems: 1,
type: "array"
},
{
items: [
{
type: "number"
},
{
type: "number"
},
{
type: "number"
}
],
maxItems: 3,
minItems: 3,
type: "array"
},
{
items: [
{
type: "number"
},
{
type: "number"
},
{
type: "number"
},
{
type: "number"
}
],
maxItems: 4,
minItems: 4,
type: "array"
},
{
type: "number"
}
],
description: "The padding applied to the screenshots of elements in px. If an array of numbers is provided, the padding is applied as defined by CSS shorthand property."
},
path: {
description: "The path to store the screenshot. This is the relative path used within the screenshot folder.",
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
clip: {
$ref: "#/definitions/ScreenshotClipArea",
description: "The clip area within the screenshot image. The clip area is defined by the top-left corner (x, y) and the width and height of the clip area."
},
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
},
padding: {
anyOf: [
{
items: [
{
type: "number"
},
{
type: "number"
}
],
maxItems: 2,
minItems: 2,
type: "array"
},
{
items: [
{
type: "number"
}
],
maxItems: 1,
minItems: 1,
type: "array"
},
{
items: [
{
type: "number"
},
{
type: "number"
},
{
type: "number"
}
],
maxItems: 3,
minItems: 3,
type: "array"
},
{
items: [
{
type: "number"
},
{
type: "number"
},
{
type: "number"
},
{
type: "number"
}
],
maxItems: 4,
minItems: 4,
type: "array"
},
{
type: "number"
}
],
description: "The padding applied to the screenshots of elements in px. If an array of numbers is provided, the padding is applied as defined by CSS shorthand property."
},
path: {
description: "The path to store the screenshot. This is the relative path used within the screenshot folder.",
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
clip: {
$ref: "#/definitions/ScreenshotClipArea",
description: "The clip area within the screenshot image. The clip area is defined by the top-left corner (x, y) and the width and height of the clip area."
},
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
},
padding: {
anyOf: [
{
items: [
{
type: "number"
},
{
type: "number"
}
],
maxItems: 2,
minItems: 2,
type: "array"
},
{
items: [
{
type: "number"
}
],
maxItems: 1,
minItems: 1,
type: "array"
},
{
items: [
{
type: "number"
},
{
type: "number"
},
{
type: "number"
}
],
maxItems: 3,
minItems: 3,
type: "array"
},
{
items: [
{
type: "number"
},
{
type: "number"
},
{
type: "number"
},
{
type: "number"
}
],
maxItems: 4,
minItems: 4,
type: "array"
},
{
type: "number"
}
],
description: "The padding applied to the screenshots of elements in px. If an array of numbers is provided, the padding is applied as defined by CSS shorthand property."
},
path: {
description: "The path to store the screenshot. This is the relative path used within the screenshot folder.",
type: "string"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The screenshot action triggers a screenshot of the current state of the application."
},
scrollTo: {
anyOf: [
{
$ref: "#/definitions/ScrollToAction"
},
{
additionalProperties: false,
properties: {
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "A scroll action scrolls the page to a specific position or element. Use the position property to scroll to a specific position or the element property to scroll to a selected DOM element."
},
text: {
anyOf: [
{
additionalProperties: false,
properties: {
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
},
value: {
description: "The value to set",
type: "string"
}
},
required: [
"selector",
"value"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
},
value: {
description: "The value to set",
type: "string"
}
},
required: [
"value"
],
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
},
value: {
description: "The value to set",
type: "string"
}
},
required: [
"value"
],
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
},
value: {
description: "The value to set",
type: "string"
}
},
required: [
"value"
],
type: "object"
}
],
description: "A text action modifies the text value of selected DOM element."
},
type: {
anyOf: [
{
additionalProperties: false,
properties: {
blur: {
"default": false,
description: "If true, the element is blurred after typing to remove the focus. The default is false.",
type: "boolean"
},
clear: {
"default": false,
description: "If true, the text input is cleared before typing. The default is false.",
type: "boolean"
},
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
},
submit: {
anyOf: [
{
additionalProperties: false,
properties: {
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The submit selector is triggered for every entry value. Use to go over multistep forms. If the submit selector is not found, the form is not automatically continued and multistep finishes."
},
value: {
anyOf: [
{
items: {
type: [
"null",
"string"
]
},
type: "array"
},
{
items: {
items: {
type: [
"null",
"string"
]
},
type: "array"
},
type: "array"
},
{
type: "string"
}
],
description: "The value to type into the selected DOM element. The value can be a string or an array of strings. If an array is provided, textfields within the selector are filled with the values in the array.\n\nFor multistep forms, the value can be an array of strings. Each array represents a step in the form. The first value in the array is typed into the first textfield, the second value in the second textfield, and so on. Configure submit selector to continue to the next step of the form."
}
},
required: [
"selector",
"value"
],
type: "object"
},
{
additionalProperties: false,
properties: {
blur: {
"default": false,
description: "If true, the element is blurred after typing to remove the focus. The default is false.",
type: "boolean"
},
clear: {
"default": false,
description: "If true, the text input is cleared before typing. The default is false.",
type: "boolean"
},
"data-cy": {
type: "string"
},
submit: {
anyOf: [
{
additionalProperties: false,
properties: {
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The submit selector is triggered for every entry value. Use to go over multistep forms. If the submit selector is not found, the form is not automatically continued and multistep finishes."
},
value: {
anyOf: [
{
items: {
type: [
"null",
"string"
]
},
type: "array"
},
{
items: {
items: {
type: [
"null",
"string"
]
},
type: "array"
},
type: "array"
},
{
type: "string"
}
],
description: "The value to type into the selected DOM element. The value can be a string or an array of strings. If an array is provided, textfields within the selector are filled with the values in the array.\n\nFor multistep forms, the value can be an array of strings. Each array represents a step in the form. The first value in the array is typed into the first textfield, the second value in the second textfield, and so on. Configure submit selector to continue to the next step of the form."
}
},
required: [
"value"
],
type: "object"
},
{
additionalProperties: false,
properties: {
blur: {
"default": false,
description: "If true, the element is blurred after typing to remove the focus. The default is false.",
type: "boolean"
},
clear: {
"default": false,
description: "If true, the text input is cleared before typing. The default is false.",
type: "boolean"
},
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
},
submit: {
anyOf: [
{
additionalProperties: false,
properties: {
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The submit selector is triggered for every entry value. Use to go over multistep forms. If the submit selector is not found, the form is not automatically continued and multistep finishes."
},
value: {
anyOf: [
{
items: {
type: [
"null",
"string"
]
},
type: "array"
},
{
items: {
items: {
type: [
"null",
"string"
]
},
type: "array"
},
type: "array"
},
{
type: "string"
}
],
description: "The value to type into the selected DOM element. The value can be a string or an array of strings. If an array is provided, textfields within the selector are filled with the values in the array.\n\nFor multistep forms, the value can be an array of strings. Each array represents a step in the form. The first value in the array is typed into the first textfield, the second value in the second textfield, and so on. Configure submit selector to continue to the next step of the form."
}
},
required: [
"value"
],
type: "object"
},
{
additionalProperties: false,
properties: {
blur: {
"default": false,
description: "If true, the element is blurred after typing to remove the focus. The default is false.",
type: "boolean"
},
clear: {
"default": false,
description: "If true, the text input is cleared before typing. The default is false.",
type: "boolean"
},
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
},
submit: {
anyOf: [
{
additionalProperties: false,
properties: {
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The submit selector is triggered for every entry value. Use to go over multistep forms. If the submit selector is not found, the form is not automatically continued and multistep finishes."
},
value: {
anyOf: [
{
items: {
type: [
"null",
"string"
]
},
type: "array"
},
{
items: {
items: {
type: [
"null",
"string"
]
},
type: "array"
},
type: "array"
},
{
type: "string"
}
],
description: "The value to type into the selected DOM element. The value can be a string or an array of strings. If an array is provided, textfields within the selector are filled with the values in the array.\n\nFor multistep forms, the value can be an array of strings. Each array represents a step in the form. The first value in the array is typed into the first textfield, the second value in the second textfield, and so on. Configure submit selector to continue to the next step of the form."
}
},
required: [
"value"
],
type: "object"
}
],
description: "A type action triggers a type event on the selected DOM element. Use to simulate typing in an input field."
},
wait: {
anyOf: [
{
$ref: "#/definitions/WaitAction"
},
{
type: "number"
}
],
description: "A wait action waits for the given time in ms or for a given chainer assertion.",
examples: [
1000,
10000
]
}
},
type: "object"
},
ForwardedOdiffOptions: {
additionalProperties: false,
properties: {
antialiasing: {
description: "If this is true, antialiased pixels are not counted to the diff of an image",
type: "boolean"
},
diffColor: {
description: "Color used to highlight different pixels in the output (in hex format e.g. #cd2cc9).",
type: "string"
},
ignoreRegions: {
description: "An array of regions to ignore in the diff.",
items: {
additionalProperties: false,
properties: {
x1: {
type: "number"
},
x2: {
type: "number"
},
y1: {
type: "number"
},
y2: {
type: "number"
}
},
required: [
"x1",
"x2",
"y1",
"y2"
],
type: "object"
},
type: "array"
},
outputDiffMask: {
description: "Output full diff image.",
type: "boolean"
},
threshold: {
description: "Color difference threshold (from 0 to 1). Less more precise.",
type: "number"
}
},
type: "object"
},
"Partial<Pick<IUser,\"userName\"|\"firstName\"|\"lastName\"|\"email\"|\"phone\"|\"id\"|\"displayName\">>": {
additionalProperties: false,
properties: {
displayName: {
description: "The display name",
type: "string"
},
email: {
description: "User email address.",
type: "string"
},
firstName: {
description: "User first name.",
type: "string"
},
id: {
description: "Uniquely identifies a user",
type: "string"
},
lastName: {
description: "User last name.",
type: "string"
},
phone: {
description: "User phone number.",
type: "string"
},
userName: {
description: "User name, unique for a given domain.\nMax: 1000 characters. Whitespaces, slashes, +$: characters not allowed",
type: "string"
}
},
type: "object"
},
ScreenshotClipArea: {
additionalProperties: false,
properties: {
height: {
description: "The height of the clip area. If negative, the height is subtracted from the viewport height.",
type: "integer"
},
width: {
description: "The width of the clip area. If negative, the width is subtracted from the viewport width.",
type: "integer"
},
x: {
description: "The x-coordinate of the top-left corner of the clip area",
minimum: 0,
type: "integer"
},
y: {
description: "The y-coordinate of the top-left corner of the clip area",
minimum: 0,
type: "integer"
}
},
required: [
"height",
"width",
"x",
"y"
],
type: "object"
},
ScreenshotSettings: {
additionalProperties: false,
properties: {
capture: {
"default": "viewport",
description: "The capturing type for the screenshot. When 'fullPage' is used, the application is captured in its entirety from top to bottom. Setting is ignored when screenshots are taken for a selected DOM element. The default is 'viewport'.\nNote that 'fullPage' screenshots will have a different height than specified in 'viewportHeight'.",
"enum": [
"fullPage",
"viewport"
],
examples: [
[
"viewport",
"fullPage"
]
],
type: "string"
},
diff: {
$ref: "#/definitions/ForwardedOdiffOptions",
description: "Options to configure the diffing of screenshots."
},
disableTimersAndAnimations: {
description: "When true, prevents JavaScript timers (setTimeout, setInterval, etc) and CSS animations from running while the screenshot is taken.",
type: "boolean"
},
overwrite: {
description: "Overwrite existing screenshots. By enabling this setting, existing screenshots might be deleted before running the screenshot workflow.",
type: "boolean"
},
padding: {
description: "The padding in px used to alter the dimensions of a screenshot of an element.",
minimum: 0,
type: "integer"
},
scale: {
description: "Whether to scale the app to fit into the browser viewport.",
type: "boolean"
},
timeouts: {
additionalProperties: false,
description: "The timeouts supported by Cypress.",
properties: {
"default": {
"default": 4000,
description: "The time, in milliseconds, to wait until most DOM based commands are considered timed out.",
examples: [
10000
],
type: "integer"
},
pageLoad: {
"default": 60000,
description: "The time, in milliseconds, to wait for the page to load. This is used for visit actions.",
examples: [
30000
],
type: "integer"
},
screenshot: {
"default": 30000,
description: "The time, in milliseconds, to wait for a response from a network request. Also applies to screenshot action.",
examples: [
60000
],
type: "integer"
}
},
type: "object"
},
viewportHeight: {
"default": 900,
description: "The height in px to use for the browser window",
minimum: 0,
type: "integer"
},
viewportWidth: {
"default": 1440,
description: "The width in px to use for the browser window",
minimum: 0,
type: "integer"
}
},
type: "object"
},
ScrollToAction: {
additionalProperties: false,
properties: {
element: {
anyOf: [
{
additionalProperties: false,
properties: {
offset: {
items: [
{
type: "number"
},
{
type: "number"
}
],
maxItems: 2,
minItems: 2,
type: "array"
},
selector: {
anyOf: [
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The selector to use to select the DOM element. The selector can be defined as string or an object with properties to select the element."
}
},
required: [
"selector"
],
type: "object"
},
{
additionalProperties: false,
properties: {
"data-cy": {
type: "string"
},
offset: {
items: [
{
type: "number"
},
{
type: "number"
}
],
maxItems: 2,
minItems: 2,
type: "array"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The language(s) this selector is valid for. If the language of the application matches the language of the selector, the selector is used to select the element.\nIf language is not supported by the selector, the selector is ignored.",
examples: [
"en",
"de",
[
"en",
"de"
]
]
},
offset: {
items: [
{
type: "number"
},
{
type: "number"
}
],
maxItems: 2,
minItems: 2,
type: "array"
}
},
type: "object"
},
{
additionalProperties: false,
properties: {
localized: {
additionalProperties: {
type: "string"
},
description: "Language key and localized selector mapping. Use for example to select elements based on the language of the application.",
examples: [
{
de: "span.label-info:not(:contains('Objekt'))",
en: "span.label-info:not(:contains('Object'))"
}
],
type: "object"
},
offset: {
items: [
{
type: "number"
},
{
type: "number"
}
],
maxItems: 2,
minItems: 2,
type: "array"
}
},
type: "object"
},
{
type: "string"
}
],
description: "The element to scroll to. Requires a selector or a DOM element. If the element is not visible, the page is scrolled to make the element visible.\nThe offset is applied when the element has been scrolled into view. The offset represents left and right pixel to scroll."
},
position: {
anyOf: [
{
items: [
{
type: "number"
},
{
type: "number"
}
],
maxItems: 2,
minItems: 2,
type: "array"
},
{
items: [
{
type: "string"
},
{
type: "string"
}
],
maxItems: 2,
minItems: 2,
type: "array"
},
{
"enum": [
"bottom",
"bottomLeft",
"bottomRight",
"center",
"left",
"right",
"top",
"topLeft",
"topRight"
],
type: "string"
}
],
description: "The position to scroll to. The default is 'top'. Provide a string, an array of strings, or a number to scroll to a specific position.",
examples: [
"top",
"bottom",
[
"top",
"100px"
],
[
0,
100
],
[
"0%",
"25%"
]
]
}
},
type: "object"
},
Visit: {
additionalProperties: false,
properties: {
selector: {
description: "The selector to wait for before taking the screenshot.",
examples: [
"c8y-drawer-outlet c8y-app-icon .c8y-icon"
],
type: "string"
},
timeout: {
description: "The timeout in ms to wait for the page to load.",
examples: [
30000
],
type: "integer"
},
url: {
description: "The URL to visit. Currently only an URI relative to the base URL is supported.",
format: "uri-reference",
type: "string"
}
},
required: [
"url"
],
type: "object"
},
WaitAction: {
additionalProperties: false,
properties: {
assert: {
anyOf: [
{
additionalProperties: false,
properties: {
chainer: {
description: "The chainer assertion to. Could be any valid Cypress chainer. The chainer is not validated and may or may not have a value to assert.",
examples: [
"have.length",
"eq",
"be.visible"
],
type: "string"
},
value: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The value to assert. The value is optional and may not be required by the chainer assertion."
}
},
required: [
"chainer"
],
type: "object"
},
{
type: "string"
}
],
description: "The chainer assertion to wait for. This translates to a Cypress get().should().\nSee https://docs.cypress.io/api/commands/should"
},
timeout: {
"default": 4000,
description: "The timeout in ms to wait for",
type: "integer"
}
},
type: "object"
}
};
var properties = {
baseUrl: {
description: "The base URL used for all relative requests.",
format: "uri",
type: "string"
},
global: {
additionalProperties: false,
description: "The global settings for all screenshots",
properties: {
capture: {
"default": "viewport",
description: "The capturing type for the screenshot. When 'fullPage' is used, the application is captured in its entirety from top to bottom. Setting is ignored when screenshots are taken for a selected DOM element. The default is 'viewport'.\nNote that 'fullPage' screenshots will have a different height than specified in 'viewportHeight'.",
"enum": [
"fullPage",
"viewport"
],
examples: [
[
"viewport",
"fullPage"
]
],
type: "string"
},
date: {
description: "The date to simulate when running the screenshot workflows",
examples: [
"2024-09-26T19:17:35+02:00"
],
format: "date-time",
type: "string"
},
diff: {
$ref: "#/definitions/ForwardedOdiffOptions",
description: "Options to configure the diffing of screenshots."
},
disableTimersAndAnimations: {
description: "When true, prevents JavaScript timers (setTimeout, setInterval, etc) and CSS animations from running while the screenshot is taken.",
type: "boolean"
},
highlightStyle: {
description: "The defaulft style to highlight elements. By default, an organge border of 2px width is used to highlight elements.",
examples: [
{
outline: "2px",
"outline-color": "#FF9300",
"outline-offset": "-2px",
"outline-style": "solid"
},
{
border: "2px solid red"
}
]
},
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "Load Cumulocity with the given language"
},
login: {
anyOf: [
{
"const": false,
type: "boolean"
},
{
type: "string"
}
],
description: "The alias referencing the username and password to login. Configure the username and password using *login*_username and *login*_password env variables. If set to false, login is disabled and visit is performed unauthenticated.",
examples: [
[
"admin",
false
]
]
},
overwrite: {
description: "Overwrite existing screenshots. By enabling this setting, existing screenshots might be deleted before running the screenshot workflow.",
type: "boolean"
},
padding: {
description: "The padding in px used to alter the dimensions of a screenshot of an element.",
minimum: 0,
type: "integer"
},
requires: {
description: "Requires the shell application to have the a version in the given range. The range must be a valid semver range. If requires is configured and shell version does not fullfill the version requirement, the screenshot workflow will be skipped.",
examples: [
"1.x, ^1.0.0, >=1.0.0 <2.0.0"
],
format: "semver-range",
type: "string"
},
scale: {
description: "Whether to scale the app to fit into the browser viewport.",
type: "boolean"
},
scrollBehavior: {
"default": false,
description: "Viewport position to which an element should be scrolled before executing commands. The default is false.",
"enum": [
"bottom",
"center",
false,
"nearest",
"top"
]
},
shell: {
description: "The shell is used to dermine the version of the application used by \"requires\" (optional)",
examples: [
"cockpit, devicemanagement, oee"
],
type: "string"
},
tags: {
description: "Tags allow grouping and filtering of screenshots (optional)",
items: {
type: "string"
},
type: "array"
},
timeouts: {
additionalProperties: false,
description: "The timeouts supported by Cypress.",
properties: {
"default": {
"default": 4000,
description: "The time, in milliseconds, to wait until most DOM based commands are considered timed out.",
examples: [
10000
],
type: "integer"
},
pageLoad: {
"default": 60000,
description: "The time, in milliseconds, to wait for the page to load. This is used for visit actions.",
examples: [
30000
],
type: "integer"
},
screenshot: {
"default": 30000,
description: "The time, in milliseconds, to wait for a response from a network request. Also applies to screenshot action.",
examples: [
60000
],
type: "integer"
}
},
type: "object"
},
user: {
anyOf: [
{
$ref: "#/definitions/Partial%3CPick%3CIUser%2C%22userName%22%7C%22firstName%22%7C%22lastName%22%7C%22email%22%7C%22phone%22%7C%22id%22%7C%22displayName%22%3E%3E"
},
{
type: "string"
}
],
description: "A user object with properties used to mock the user information in Cumulocity. This is useful to anonymize the user information in the screenshots."
},
viewportHeight: {
"default": 900,
description: "The height in px to use for the browser window",
minimum: 0,
type: "integer"
},
viewportWidth: {
"default": 1440,
description: "The width in px to use for the browser window",
minimum: 0,
type: "integer"
},
visitWaitSelector: {
"default": "c8y-drawer-outlet c8y-app-icon .c8y-icon",
description: "The selector to wait for when visiting a page",
examples: [
"c8y-drawer-outlet c8y-app-icon .c8y-icon"
],
type: "string"
}
},
type: "object"
},
screenshots: {
description: "The screenshot workflows",
items: {
additionalProperties: false,
properties: {
actions: {
anyOf: [
{
$ref: "#/definitions/Action"
},
{
items: {
$ref: "#/definitions/Action"
},
type: "array"
}
],
description: "The actions to perform in the screenshot workflow. The last actioncis always a screenshot action. If no actions are defined or last actions is not a screenshot action, a screenshot is taken of the current state of the application."
},
date: {
description: "The date to simulate when running the screenshot workflows",
examples: [
"2024-09-26T19:17:35+02:00"
],
format: "date-time",
type: "string"
},
image: {
description: "The name of the screenshot image as relative path",
examples: [
"/images/cockpit/dashboard.png"
],
type: "string"
},
language: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "Load Cumulocity with the given language"
},
login: {
anyOf: [
{
"const": false,
type: "boolean"
},
{
type: "string"
}
],
description: "The alias referencing the username and password to login. Configure the username and password using *login*_username and *login*_password env variables. If set to false, login is disabled and visit is performed unauthenticated.",
examples: [
[
"admin",
false
]
]
},
only: {
description: "Run only this screenshot workflow and all other workflows that have only setting enabled",
type: "boolean"
},
requires: {
description: "Requires the shell application to have the a version in the given range. The range must be a valid semver range. If requires is configured and shell version does not fullfill the version requirement, the screenshot workflow will be skipped.",
examples: [
"1.x, ^1.0.0, >=1.0.0 <2.0.0"
],
format: "semver-range",
type: "string"
},
scrollBehavior: {
"default": false,
description: "Viewport position to which an element should be scrolled before executing commands. The default is false.",
"enum": [
"bottom",
"center",
false,
"nearest",
"top"
]
},
settings: {
$ref: "#/definitions/ScreenshotSettings",
description: "The configuration and settings of the screenshot"
},
shell: {
description: "The shell is used to dermine the version of the application used by \"requires\" (optional)",
examples: [
"cockpit, devicemanagement, oee"
],
type: "string"
},
skip: {
description: "Skip this screenshot workflow",
type: "boolean"
},
tags: {
description: "Tags allow grouping and filtering of screenshots (optional)",
items: {
type: "string"
},
type: "array"
},
title: {
anyOf: [
{
items: {
type: "string"
},
type: "array"
},
{
type: "string"
}
],
description: "The title of the screenshot workflow. The title is used to group the screenshots. To provide a hierarchy of titles, use an array of strings."
},
user: {
anyOf: [
{
$ref: "#/definitions/Partial%3CPick%3CIUser%2C%22userName%22%7C%22firstName%22%7C%22lastName%22%7C%22email%22%7C%22phone%22%7C%22id%22%7C%22displayName%22%3E%3E"
},
{
type: "string"
}
],
description: "A user object with properties used to mock the user information in Cumulocity. This is useful to anonymize the user information in the screenshots."
},
visit: {
anyOf: [
{
$ref: "#/definitions/Visit"
},
{
type: "string"
}
],
description: "The URI to visit. This typically a relative path to the baseUrl.",
examples: [
"/apps/cockpit/index.html#/"
]
}
},
required: [
"image",
"visit"
],
type: "object"
},
type: "array"
},
selectors: {
anyOf: [
{
additionalProperties: {
type: "string"
},
type: "object"
},
{
items: {
additionalProperties: {
type: "string"
},
type: "object"
},
type: "array"
}
],
description: "Definition of shared selectors to use in the screenshot workflows"
},
title: {
description: "The title used for root group of screenshot workflows",
type: "string"
}
};
var required = [
"screenshots"
];
var type = "object";
var schema = {
$schema: $schema,
additionalProperties: additionalProperties,
definitions: definitions,
properties: properties,
required: required,
type: type
};
/**
* Error thrown when a C8yPactMatcher fails to match two objects.
* Contains the actual and expected values, the key that failed to match and
* the key path of the property that failed to match.
* The key path is a string representation of the path to the property that failed to match.
* For example: "body > id" for a property "id" in the "body" object.
* This error is used to provide detailed information about the match failure.
*/
class C8yPactMatchError extends Error {
constructor(message, options) {
super(message);
this.name = "C8yPactMatchError";
this.actual = options.actual;
this.expected = options.expected;
this.key = options.key;
this.keyPath = options.keyPath;
this.schema = options.schema;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, C8yPactMatchError);
}
}
}
/**
* Default implementation of C8yPactMatcher to match C8yPactRecord objects. Pacts
* are matched by comparing the properties of the objects using property matchers.
* If no property matcher is configured for a property, the property will be matched
* by equality. Disable Cypress.c8ypact.config.strictMatching to ignore properties that are
* missing in matched objects. In case objects do not match an C8yPactError is thrown.
*/
class C8yDefaultPactMatcher {
constructor(propertyMatchers = {
body: new C8yPactBodyMatcher(),
requestBody: new C8yPactBodyMatcher(),
duration: new C8yNumberMatcher(),
date: new C8yIgnoreMatcher(),
Authorization: new C8yIgnoreMatcher(),
auth: new C8yIgnoreMatcher(),
options: new C8yIgnoreMatcher(),
createdObject: new C8yIgnoreMatcher(),
location: new C8yIgnoreMatcher(),
url: new C8yIgnoreMatcher(),
"X-XSRF-TOKEN": new C8yIgnoreMatcher(),
lastMessage: new C8yISODateStringMatcher(),
}, options) {
this.propertyMatchers = {};
this.propertyMatchers = propertyMatchers;
this.options = options;
}
match(obj1, obj2, options) {
if (obj1 === obj2)
return true;
options = _.defaults({}, options, this.options, C8yDefaultPactMatcher.options);
const parents = options?.parents ?? [];
const strictMatching = options?.strictMatching ?? false;
const ignorePrimitiveArrayOrder = options?.ignorePrimitiveArrayOrder ?? true;
const matchSchemaAndObject = options?.matchSchemaAndObject ?? false;
const schemaMatcher = options?.schemaMatcher || C8yDefaultPactMatcher.schemaMatcher;
const addLoggerProps = (props, message, key) => {
if (options?.loggerProps) {
options.loggerProps.error = message;
options.loggerProps.key = key;
options.loggerProps.keypath = keyPath(key);
options.loggerProps.objects =
key && _.isPlainObject(obj1) && _.isPlainObject(obj2)
? [_.pick(obj1, [key]), _.pick(obj2, [key])]
: [obj1, obj2];
}
};
const throwPactError = (message, key) => {
const newErr = new C8yPactMatchError(`Pact validation failed${options?.requestId ? ` for request ${options.requestId}` : ""}! ${message}`, {
actual: obj1,
expected: obj2,
...(key != null ? { key, keyPath: keyPath(key) } : {}),
});
addLoggerProps(options?.loggerProps, newErr.message, key);
throw newErr;
};
const throwSchemaError = (message, key, schema, value) => {
const newErr = new C8yPactMatchError(`Pact validation failed${options?.requestId ? ` for request ${options.requestId}` : ""}! ${message}`, {
actual: value ?? obj1,
expected: schema ?? obj2,
key,
keyPath: keyPath(key),
schema: schema,
});
addLoggerProps(options?.loggerProps, newErr.message, key);
throw newErr;
};
const keyPath = (k) => {
if (_.isArray(k)) {
const segments = k.map((segment) => segment.toString());
return segments.join(" > ");
}
return `${[...parents, ...(k ? [k] : [])].join(" > ")}`;
};
const isArrayOfPrimitivesOrNull = (value) => {
if (!_.isArray(value)) {
return false;
}
const primitiveTypes = ["undefined", "boolean", "number", "string"];
return (value.filter((p) => primitiveTypes.includes(typeof p) || p === null)
.length === value.length);
};
const matchArraysOfPrimitives = (value, pact, parents) => {
if (value.length !== pact.length) {
throwPactError(`Arrays with key "${keyPath(parents)}" have different lengths.`, keyPath(parents));
}
const diff = [];
const sortedValue = ignorePrimitiveArrayOrder
? [...value].sort()
: [...value];
const sortedPact = ignorePrimitiveArrayOrder
? [...pact].sort()
: [...pact];
for (let i = 0; i < sortedValue.length; i++) {
if (i >= sortedValue.length ||
i >= sortedPact.length ||
sortedValue[i] !== sortedPact[i]) {
diff.push(i);
}
}
if (diff.length === 0) {
return;
}
else {
throwPactError(`Arrays with key "${keyPath(parents)}" have mismatches at indices "${diff}".`, keyPath(parents));
}
};
if (_.isString(obj1) && _.isString(obj2) && !_.isEqual(obj1, obj2)) {
throwPactError(`"${keyPath()}" text did not match.`);
}
if (!_.isObject(obj1) || !_.isObject(obj2)) {
throwPactError(`Expected 2 objects as input for matching, but got "${typeof obj1}" and ${typeof obj2}".`);
}
if (_.isArray(obj1) && _.isArray(obj2)) {
if (obj1.length !== obj2.length) {
throwPactError(`Arrays at "${_.isEmpty(parents) ? "root" : keyPath()}" have different lengths.`);
}
}
if (_.isArray(obj1) !== _.isArray(obj2)) {
throwPactError(`Type mismatch at "${_.isEmpty(parents) ? "root" : keyPath()}". Expected ${_.isArray(obj2) ? "array" : "object"} but got ${_.isArray(obj1) ? "array" : "object"}.`);
}
// get keys of objects without schema keys and schema keys separately
const objectKeys = Object.keys(obj1).filter((k) => !this.isSchemaMatcherKey(k));
const schemaKeys = Object.keys(obj2).filter((k) => this.isSchemaMatcherKey(k));
// normalize pact keys and remove keys that have a schema defined
// we do not want for example body and $body
const pactKeys = matchSchemaAndObject === true
? Object.keys(obj2)
: Object.keys(obj2).reduce((acc, key) => {
if (!schemaKeys.includes(`$${key}`)) {
acc.push(key);
}
return acc;
}, []);
if (_.isEmpty(objectKeys) && _.isEmpty(pactKeys)) {
return true;
}
const removeSchemaPrefix = (key) => this.isSchemaMatcherKey(key) ? key.slice(1) : key;
const findActualKey = (obj, keyToFind) => {
if (!options?.ignoreCase)
return keyToFind;
if (obj == null || !_.isObject(obj))
return keyToFind;
const actualKey = Object.keys(obj).find((k) => k.toLowerCase() === keyToFind.toLowerCase());
return actualKey ?? keyToFind;
};
// if strictMatching is disabled, only check properties of the pact for object matching
// strictMatching for schema matching is considered within the matcher -> schema.additionalProperties
const keys = strictMatching === false ? pactKeys : objectKeys;
// When strictMatching is enabled, also ensure every pact key is present in the response.
// The main loop (iterating objectKeys) only catches extra response keys not in the pact;
// this extra pass catches pact keys that are absent from the response.
if (strictMatching === true) {
for (const pactKey of pactKeys) {
if (this.isSchemaMatcherKey(pactKey))
continue;
if (!this.isKeyPathInObject(objectKeys, pactKey, options?.ignoreCase)) {
throwPactError(`"${keyPath(pactKey)}" not found in response object.`);
}
}
}
for (const key of keys) {
// schema is always defined on the pact object - needs special consideration
const isSchema = this.isSchemaMatcherKey(key) || schemaKeys.includes(`$${key}`);
// Resolve actual keys with correct casing when ignoreCase is enabled
// obj1 is always the actual response, obj2 is always the pact/record
const valueSourceObj = obj1;
const pactSourceObj = obj2;
const keyForValue = findActualKey(valueSourceObj, removeSchemaPrefix(key));
const keyForPact = findActualKey(pactSourceObj, isSchema && !key.startsWith("$") ? `$${key}` : key);
const value = _.get(valueSourceObj, keyForValue);
let pact = _.get(pactSourceObj, keyForPact);
if (!isSchema &&
!this.isKeyPathInObject(strictMatching ? pactKeys : objectKeys, key, options?.ignoreCase)) {
if (strictMatching) {
throwPactError(`"${keyPath(key)}" not found in pact object.`);
}
else {
// strictMatching: false — only skip when the key is genuinely absent from the
// response (no match even case-insensitively). If the key exists with different
// casing but ignoreCase: false, surface the casing mismatch by throwing.
if (this.isKeyPathInObject(objectKeys, key, true)) {
throwPactError(`"${keyPath(key)}" not found in response object.`);
}
continue;
}
}
if (isSchema) {
const errorKey = removeSchemaPrefix(key);
if (!schemaMatcher) {
throwSchemaError(`No schema matcher registered to validate "${keyPath(errorKey)}".`, errorKey, pact, value);
}
try {
if (!schemaMatcher.match(value, pact, strictMatching)) {
throwSchemaError(`Schema for "${keyPath(errorKey)}" does not match.`, errorKey, pact, value);
}
}
catch (error) {
throwSchemaError(`Schema for "${keyPath(errorKey)}" does not match (${error?.message ?? error}).`, errorKey, pact, value);
}
if (!matchSchemaAndObject) {
continue;
}
const keyForSchemaAndObject = findActualKey(obj2, removeSchemaPrefix(key));
pact = _.get(obj2, keyForSchemaAndObject);
}
if (this.getPropertyMatcher(key, options?.ignoreCase) != null) {
if (!strictMatching && !value) {
continue;
}
try {
const result = this.getPropertyMatcher(key, options?.ignoreCase)?.match(value, pact, _.extend(options, { parents: [...parents, key] }));
if (!result)
throw new Error("");
}
catch (error) {
// calling match recursively requires to pass the root error
if (_.get(error, "name") === "C8yPactError" ||
_.get(error, "name") === "C8yPactMatchError") {
throw error;
}
else {
throwPactError(`Values for "${keyPath(key)}" do not match.${error != null ? " " + (error?.message ?? error) : ""}`, key);
}
}
}
else if (isArrayOfPrimitivesOrNull(value) &&
isArrayOfPrimitivesOrNull(pact)) {
matchArraysOfPrimitives(value, pact, [...parents, key]);
}
else if (_.isArray(value) && _.isArray(pact)) {
if (value.length !== pact.length) {
throwPactError(`Arrays with key "${keyPath(key)}" have different lengths.`, key);
}
for (let i = 0; i < value.length; i++) {
if (isArrayOfPrimitivesOrNull(value[i]) &&
isArrayOfPrimitivesOrNull(pact[i])) {
matchArraysOfPrimitives(value[i], pact[i], [...parents, key, i]);
}
else {
this.match(value[i], pact[i], _.extend(options, { parents: [...parents, key, i] }));
}
}
}
else if (_.isObjectLike(value) && _.isObjectLike(pact)) {
if (isArrayOfPrimitivesOrNull(value) &&
isArrayOfPrimitivesOrNull(pact)) {
matchArraysOfPrimitives(value, pact, [...parents, key]);
}
else {
this.match(value, pact, _.extend(options, { parents: [...parents, key] }));
}
}
else {
if (value != null && pact != null && !_.isEqual(value, pact)) {
throwPactError(`Values for "${keyPath(key)}" do not match.`, key);
}
}
}
return true;
}
/**
* Check if a key is a schema matcher key (starts with $ but is not a standard JSON Schema keyword)
*/
isSchemaMatcherKey(key) {
if (!key.startsWith("$")) {
return false;
}
return !C8yDefaultPactMatcher.JSON_SCHEMA_KEYWORDS.has(key);
}
isKeyPathInObject(keys, keyPath, ignoreCase = false) {
if (!Array.isArray(keys)) {
return false;
}
if (ignoreCase) {
const lowerKeyPath = keyPath.toLowerCase();
return keys.some((item) => typeof item === "string" && item.toLowerCase() === lowerKeyPath);
}
return keys.includes(keyPath);
}
/**
* Returns the property matcher for the given property name.
* @param key The property name to get the matcher for.
* @param ignoreCase Whether to ignore the case of the property name.
*/
getPropertyMatcher(key, ignoreCase = false) {
if (ignoreCase) {
return util.get_i(this.propertyMatchers, key);
}
return this.propertyMatchers[key];
}
/**
* Adds a new property matcher for the given property name.
*/
addPropertyMatcher(propertyName, matcher) {
this.propertyMatchers[propertyName] = matcher;
}
/**
* Removes the property matcher for the given property name.
*/
removePropertyMatcher(propertyName) {
delete this.propertyMatchers[propertyName];
}
}
/**
* Standard JSON Schema keywords that start with $ but are not schema matcher keys.
* These should be treated as regular object properties.
* @see https://json-schema.org/understanding-json-schema/reference
*/
C8yDefaultPactMatcher.JSON_SCHEMA_KEYWORDS = new Set([
"$schema",
"$id",
"$ref",
"$comment",
"$defs",
"$vocabulary",
"$anchor",
"$dynamicRef",
"$dynamicAnchor",
"$recursiveRef",
"$recursiveAnchor",
]);
/**
* Extends C8yDefaultPactMatcher with default property matchers for Cumulocity
* response bodies. It has rules configured at least for the following properties:
* id, statistics, lastUpdated, creationTime, next, self, password, owner, tenantId
* and lastPasswordChange. It is registered for the properties body and requestBody.
*/
class C8yPactBodyMatcher extends C8yDefaultPactMatcher {
constructor(propertyMatchers = {}) {
super(propertyMatchers);
this.addPropertyMatcher("id", new C8ySameTypeMatcher());
this.addPropertyMatcher("statistics", new C8yIgnoreMatcher());
this.addPropertyMatcher("lastUpdated", new C8yISODateStringMatcher());
this.addPropertyMatcher("creationTime", new C8yISODateStringMatcher());
this.addPropertyMatcher("next", new C8yIgnoreMatcher());
this.addPropertyMatcher("self", new C8yIgnoreMatcher());
this.addPropertyMatcher("password", new C8yIgnoreMatcher());
this.addPropertyMatcher("owner", new C8ySameTypeMatcher());
this.addPropertyMatcher("tenantId", new C8yIgnoreMatcher());
this.addPropertyMatcher("lastPasswordChange", new C8yISODateStringMatcher());
}
}
class C8yNumberMatcher {
match(obj1, obj2) {
[obj1, obj2].forEach((n) => {
if (!_.isNumber(n) || _.isNaN(n)) {
throw new Error(`Value "${obj1}" is not a number.`);
}
});
return true;
}
}
class C8yIgnoreMatcher {
match() {
return true;
}
}
class C8ySameTypeMatcher {
match(obj1, obj2) {
const result = typeof obj1 === typeof obj2;
if (!result) {
throw new Error(`Values are not of same type. Expected ${typeof obj1} but got ${typeof obj2}`);
}
return result;
}
}
class C8yISODateStringMatcher {
match(obj1, obj2) {
// validate regex as parseISO does not throw an error for invalid dates
// and is not strict enough for our use case
// https://regex101.com/library/6gJsuQ?filterFlavors=javascript&page=9
const isoRegex = new RegExp(/^((\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\d|3[01])|(0[469]|11)-(0[1-9]|[12]\d|30)|(02)-(0[1-9]|1\d|2[0-8])))T([01]\d|2[0-3]):[0-5]\d:[0-5]\d\.\d{3}([+-]([01]\d|2[0-3]):[0-5]\d|Z)$/);
[obj1, obj2].forEach((obj) => {
if (!_.isString(obj)) {
throw new Error(`Value "${obj}" is not a string.`);
}
if (!isoRegex.test(obj)) {
throw new Error(`Value "${obj}" is not a valid ISO date string.`);
}
});
const d1 = datefns__namespace.parseISO(obj1);
const d2 = datefns__namespace.parseISO(obj2);
return datefns__namespace.isValid(d1) && datefns__namespace.isValid(d2);
}
}
/**
* Default implementation of C8ySchemaMatcher using AJV. By default
* json-schema-draft-07 meta schema is used. Other meta schema can be added
* by passing in constructor. If options.strictMatching is disabled for match,
* additionalProperties will be set to true allowing additional properties
* in the object to match the schema.
*/
class C8yAjvSchemaMatcher {
constructor(metas, strict = false) {
if (_.isBoolean(metas)) {
{
strict = metas;
metas = undefined;
}
}
//https://ajv.js.org/options.html
this.ajv = new Ajv({ strict, allowUnionTypes: true });
addFormats(this.ajv, [
"uri",
"uri-reference",
"url",
"uuid",
"hostname",
"date-time",
"date",
"password",
]);
this.ajv.addFormat("integer", {
type: "number",
validate: (x) => _.isInteger(x),
});
this.ajv.addFormat("boolean", {
validate: (x) => _.isBoolean(x),
});
this.ajv.addFormat("boolean", {
type: "string",
validate: (x) => _.isString(x) && ["true", "false"].includes(_.lowerCase(x)),
});
this.ajv.addFormat("semver-range", {
type: "string",
validate: (x) => {
return semver__namespace.validRange(x) != null;
},
});
this.ajv.addFormat("semver-version", {
type: "string",
validate: (x) => {
return semver__namespace.valid(x) != null;
},
});
if (metas && _.isArrayLike(metas)) {
metas.forEach((m) => {
this.ajv.addMetaSchema(m);
});
}
}
match(obj, schema, strictMatching) {
if (!schema)
return false;
const schemaClone = _.cloneDeep(schema);
if (strictMatching != null) {
this.updateAdditionalProperties(schemaClone, !strictMatching);
}
const valid = this.ajv.validate(schemaClone, obj);
if (!valid) {
throw new C8yPactMatchError(this.ajv.errorsText(), {
actual: obj,
expected: schemaClone,
});
}
return valid;
}
updateAdditionalProperties(schema, value) {
if (_.isObjectLike(schema)) {
if ("additionalProperties" in schema || schema.type === "object") {
schema.additionalProperties = value;
}
Object.values(schema).forEach((v) => {
this.updateAdditionalProperties(v, value);
});
}
else if (_.isArray(schema)) {
schema.forEach((v) => {
this.updateAdditionalProperties(v, value);
});
}
}
}
function isURL(obj) {
return obj instanceof URL;
}
function removeBaseUrlFromString(url, baseUrl) {
if (!url || !baseUrl) {
return url;
}
let normalizedBaseUrl = _.clone(baseUrl);
while (normalizedBaseUrl.endsWith("/")) {
normalizedBaseUrl = normalizedBaseUrl.slice(0, -1);
}
let result = url.replace(normalizedBaseUrl, "");
if (_.isEmpty(result)) {
result = "/";
}
return result;
}
function removeBaseUrlFromRequestUrl(record, baseUrl) {
if (!record?.request?.url || !baseUrl || !_.isString(baseUrl)) {
return;
}
record.request.url = removeBaseUrlFromString(record.request.url, baseUrl);
}
/**
* Checks if the given URL is an absolute URL.
* @param url The URL to check.
* @returns True if the URL is an absolute URL, false otherwise.
*/
function isAbsoluteURL(url) {
if (!url || !_.isString(url) || _.isEmpty(url))
return false;
return /^https?:\/\//i.test(url);
}
/**
* Validates the base URL and throws an error if the base URL is not an absolute URL. This
* is required as commands expect an absolute URL as baseUrl. Will not fail for undefined values.
* `Cypress.config().baseUrl` is validated by Cypress itself and throw an error.
*
* @param baseUrl The url to validate.
*/
function validateBaseUrl(baseUrl) {
if (baseUrl != null && !isAbsoluteURL(baseUrl)) {
const error = new Error(`Invalid value for base url. '${baseUrl}' must be an absolute URL or undefined.`);
error.name = "C8yPactError";
throw error;
}
}
/**
* Normalizes a URL to ensure it has a protocol and proper trailing slash.
* If no protocol is present, HTTPS is added by default.
* If the URL has no path component, a trailing slash is appended.
*
* @param url - The URL string to normalize
* @returns The normalized URL with HTTPS protocol and trailing slash if appropriate, or undefined for invalid input
*/
function normalizeBaseUrl(url) {
if (!url || !_.isString(url)) {
return undefined;
}
const trimmedUrl = url.trim();
if (!trimmedUrl) {
return undefined;
}
let normalizedUrl;
// Check if URL already has a protocol
if (/^https?:\/\//i.test(trimmedUrl)) {
normalizedUrl = trimmedUrl;
}
else {
// Add https:// if no protocol is present
normalizedUrl = `https://${trimmedUrl}`;
}
try {
const urlObj = new URL(normalizedUrl);
// remove all components other than protocol, host
normalizedUrl = `${urlObj.protocol}//${urlObj.host}`;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to normalize base url ${url}. ${errorMessage}`);
}
return normalizedUrl;
}
/**
* Converts the given URL to a string.
* @param url The URL or RequestInfo to convert.
* @returns The URL as a string.
*/
function toUrlString(url) {
if (_.isString(url)) {
return url;
}
else if (url instanceof URL) {
return url.toString();
}
else if (url instanceof Request) {
return url.url;
}
else {
throw new Error(`Type for URL not supported. Expected URL, string or Request, but found $'{typeof url}}'.`);
}
}
exports.C8yAjvSchemaMatcher = C8yAjvSchemaMatcher;
exports.C8yDefaultPactMatcher = C8yDefaultPactMatcher;
exports.isAbsoluteURL = isAbsoluteURL;
exports.isURL = isURL;
exports.normalizeBaseUrl = normalizeBaseUrl;
exports.removeBaseUrlFromRequestUrl = removeBaseUrlFromRequestUrl;
exports.schema = schema;
exports.toUrlString = toUrlString;
exports.validateBaseUrl = validateBaseUrl;