UNPKG

cumulocity-cypress

Version:
254 lines (253 loc) 8.13 kB
/// <reference types="cypress" /> // workaround for lodash import in Cypress nodejs typescript runtime and browser import lodash1 from "lodash"; import * as lodash2 from "lodash"; const _ = lodash1 || lodash2; import { isAbsoluteURL } from "../url"; import { get_i } from "../util"; export const C8yPactModeValues = [ "record", "recording", "apply", "forward", "disabled", "mock", ]; export const C8yPactRecordingModeValues = [ "refresh", "append", "new", "replace", ]; export const C8yPactObjectKeys = ["records", "info", "id"]; export function isValidPactId(value) { if (value == null || value.length > 1000 || !_.isString(value)) return false; const validPactIdRegex = /^[a-zA-Z0-9_-]+(__[a-zA-Z0-9_-]+)*$/; return validPactIdRegex.test(value); } /** * Creates an C8yPactID for a given string or array of strings. * @param value The string or array of strings to convert to a pact id. * @returns The pact id. */ export function pactId(value) { let result = ""; const suiteSeparator = "__"; const normalize = (value) => value .split(suiteSeparator) .map((v) => _.words(_.deburr(v), /[a-zA-Z0-9_-]+/g).join("_")) .join(suiteSeparator); if (value != null && _.isArray(value)) { result = value.map((v) => normalize(v)).join(suiteSeparator); } else if (value != null && _.isString(value)) { result = normalize(value); } if (result == null || _.isEmpty(result)) { return !value ? value : undefined; } return result; } /** * Validate the given pact mode. Throws an error if the mode is not supported * or undefined. * @param mode The pact mode to validate. */ export function validatePactMode(mode) { if (mode != null) { const values = Object.values(C8yPactModeValues); if (!_.isString(mode) || _.isEmpty(mode) || !values.includes(mode.toLowerCase())) { const error = new Error(`Unsupported pact mode: "${mode}". Supported values are: ${values.join(", ")} or undefined.`); error.name = "C8yPactError"; throw error; } } } /** * Validate the given pact recording mode. Throws an error if the mode is not supported * or undefined. * @param mode The pact recording mode to validate. */ export function validatePactRecordingMode(mode) { if (mode != null) { const keys = Object.values(C8yPactRecordingModeValues); if (!_.isString(mode) || _.isEmpty(mode) || !keys.includes(mode.toLowerCase())) { const error = new Error(`Unsupported recording mode: "${mode}". Supported values are: ${keys.join(", ")} or undefined.`); error.name = "C8yPactError"; throw error; } } } /** * Checks if the given object is a C8yPact. This also includes checking * all records to be valid C8yPactRecord instances. * * @param obj The object to check. * @returns True if the object is a C8yPact, false otherwise. */ export function isPact(obj) { return (_.isObjectLike(obj) && "info" in obj && _.isObjectLike(_.get(obj, "info")) && "records" in obj && _.isArray(_.get(obj, "records")) && _.every(_.get(obj, "records"), isPactRecord) && _.isFunction(_.get(obj, "nextRecord")) && _.isFunction(_.get(obj, "nextRecordMatchingRequest")) && _.isFunction(_.get(obj, "appendRecord")) && _.isFunction(_.get(obj, "replaceRecord"))); } /** * Checks if the given object is a C8yPactRecord. * * @param obj The object to check. * @returns True if the object is a C8yPactRecord, false otherwise. */ export function isPactRecord(obj) { return (_.isObjectLike(obj) && "request" in obj && _.isObjectLike(_.get(obj, "request")) && "response" in obj && _.isObjectLike(_.get(obj, "response")) && _.isFunction(_.get(obj, "toCypressResponse"))); } /** * Checks if the given object is a Cypress.Response. * * @param obj The object to check. * @returns True if the object is a Cypress.Response, false otherwise. */ export function isCypressResponse(obj) { return (_.isObjectLike(obj) && "body" in obj && "status" in obj && "headers" in obj && "requestHeaders" in obj && "duration" in obj && "url" in obj && "isOkStatusCode" in obj && // not a window.Response or Client.FetchResponse !("ok" in obj || "arrayBuffer" in obj)); } /** * Checks if the given object is a C8yPactError. A C8yPactError is an error * with the name "C8yPactError". * * @param error The object to check. * @returns True if the object is a C8yPactError, false otherwise. */ export function isPactError(error) { return _.isError(error) && _.get(error, "name") === "C8yPactError"; } function isDefined(value) { return !_.isUndefined(value); } /** * Converts a Cypress.Response to a C8yPactRequest. */ export function toPactRequest(response) { if (!response) return response; const result = _.pickBy(_.mapKeys(_.pick(response, ["url", "method", "requestHeaders", "requestBody"]), (v, k) => { if (_.isEqual(k, "requestHeaders")) return "headers"; if (_.isEqual(k, "requestBody")) return "body"; return k; }), isDefined); if (_.isEmpty(result)) return undefined; return result; } /** * Converts a Cypress.Response to a C8yPactResponse. */ export function toPactResponse(response) { if (!response) return response; const result = _.pickBy(_.pick(response, [ "status", "statusText", "body", "headers", "duration", "isOkStatusCode", "allRequestResponses", "$body", ]), isDefined); if (_.isEmpty(result)) return undefined; return result; } /** * Returns the value of the environment variable with the given name. The function * tries to find the value in the global `process.env` or `Cypress.env()`. If `env` * is provided, the function uses the given object as environment. * * The function tries to find the value in the following order: * - `name` * - `camelCase(name)` * - `CYPRESS_name` * - `name.replace(/^C8Y_/i, "")` * - `CYPRESS_camelCase(name)` * - `CYPRESS_camelCase(name.replace(/^C8Y_/i, ""))` * * @param name The name of the environment variable. * @param env The environment object to use. Default is `process.env` or `Cypress.env()` * * @returns The value of the environment variable or `undefined` if not found. */ export function getEnvVar(name, env) { if (!name) return undefined; const e = env || (typeof window !== "undefined" && window.Cypress ? Cypress.env() : process.env); function getFromEnv(key) { return e[key]; } function getForName(name) { return getFromEnv(name) || getFromEnv(`CYPRESS_${name}`); } const plainName = name.replace(/^C8Y_/i, ""); const camelCasedName = _.camelCase(name).replace(/^c8Y/i, "c8y"); const camelCasedPlainName = _.camelCase(plainName); return (getForName(name) || getForName(camelCasedName) || getForName(plainName) || getForName(camelCasedPlainName)); } export function isOneOfStrings(value, values) { if (!_.isString(value) || _.isEmpty(value)) return false; return values.includes(value.toLowerCase()); } export function getCreatedObjectId(response) { let newId = response?.body?.id; if (newId) { return newId; } else { const location = get_i(response, "headers.location"); if (isAbsoluteURL(location)) { try { const url = new URL(location); const pathSegments = url?.pathname.split("/").filter(Boolean); newId = pathSegments?.pop(); if (newId != null) { return decodeURIComponent(newId); } } catch { // do nothing } } } return undefined; }