UNPKG

cumulocity-cypress

Version:
310 lines (309 loc) 10.2 kB
/// <reference types="cypress" /> import { BasicAuth, CookieAuth } from "@c8y/client"; import { isAuthOptions } from "../shared/auth"; import { getEnvVar } from "../shared/c8ypact/c8ypact"; import { toSemverVersion } from "../shared/versioning"; import { get_i } from "../shared/util"; const { _ } = Cypress; /** * Helper to normalize any given arguments and Cypress `prevSubject`. * * When chaining commands, Cypress will pass result from previous subject * (parent) as first argument. In case of optional `prevSubject` Cypress will pass * `null` as first argument if previous command did not yield a result value. * * Depending on the hierarchy of chained commands, the structure of the * `prevSubject` argument will be different. * * Supported options * 1. [<prevSubject>, arguments] * 2. {"<index>": [<prevSubject>, arguments], "<index>": arguments } * * Structure of 2) depends on the command chainer. */ export function normalizedArguments(args) { if (!args) return []; let result = []; if (_.isArray(args)) { result = args; if (args[0] != null && _.isArray(result[0])) { const subjects = _.flatten(result[0]); result = subjects.concat(result.slice(1)); } } else if (_.isObjectLike(args)) { const values = Object.values(args); result = _.flatten(values[0]).concat(values.slice(1)); } return _.dropWhile(result, (a) => !a); } /** * Get `normalizedArguments` and insert auth options from * env variables at the beginning of the arguments. */ export function normalizedArgumentsWithAuth(args) { if (!args) return [undefined]; const normalized = normalizedArguments(args); if (_.isEmpty(normalized) || (!_.isEmpty(normalized) && !isAuthOptions(normalized[0]))) { const auth = getAuthOptionsFromEnv(); if (auth) { normalized.unshift(auth); } else { if (!args[0]) { normalized.unshift(undefined); } } } return normalized; } export function normalizedC8yclientArguments(args) { if (!args) return [undefined]; const normalized = normalizedArgumentsWithAuth(args); if (getCookieAuthFromEnv() != null && args[0] == null) { normalized[0] = undefined; } return normalized; } export function getCookieAuthFromEnv() { const cookieAuth = new CookieAuth(); const token = get_i(cookieAuth.getFetchOptions({}), "headers.X-XSRF-TOKEN"); if (!token || _.isEmpty(token)) { return undefined; } return cookieAuth; } export function getXsrfToken() { const cookieAuth = new CookieAuth(); const token = get_i(cookieAuth.getFetchOptions({}), "headers.X-XSRF-TOKEN"); if (token != null && !_.isEmpty(token)) { return token; } return undefined; } export function getAuthOptionsFromEnv() { // check window.localStorage for __auth item const win = cy.state("window"); const authString = win.localStorage.getItem("__auth"); if (authString && _.isString(authString) && !_.isEmpty(authString)) { const authObj = getAuthOptionsFromArgs(JSON.parse(authString)); if (isAuthOptions(authObj)) { return authObj; } } // check auth options from test case annotation // configured via it("...", {auth: {...}}, ...) const auth = getAuthOptionsFromArgs(Cypress.config().auth); if (isAuthOptions(auth)) { return auth; } // check first environment variables const user = Cypress.env(`C8Y_USERNAME`); const password = Cypress.env(`C8Y_PASSWORD`); if (!_.isEmpty(user) && !_.isEmpty(password)) { return authWithTenant({ user, password, }); } return undefined; } export function getAuthOptions(...args) { if (!args || !args.length || (args[0] == null && args.length === 1)) { return getAuthOptionsFromEnv(); } // first args are null for every { prevSubject: option } command in the // call hierarchy. remove all null args from the beginning. if (args[0] == null) { args = _.dropWhile(args, (a) => !a); } else if (_.isArray(args[0])) { args = _.flatten(args[0]); } const auth = getAuthOptionsFromArgs(...args); if (isAuthOptions(auth)) { return authWithTenant(auth); } else if (args.length === 1 && _.isString(args[0])) { return undefined; } return getAuthOptionsFromEnv(); } export function userAliasFromArgs(...args) { if (!args || !args.length) return undefined; if (args[0] == null) { args = _.dropWhile(args, (a) => !a); } else if (_.isArray(args[0])) { args = _.flatten(args[0]); } return args.length === 1 && _.isString(args[0]) ? args[0] : undefined; } function getAuthOptionsFromArgs(...args) { // do not call getAuthOptionsFromEnv() in here! // getAuthOptions("admin") // return envs admin_username | admin, admin_password if (!_.isEmpty(args) && _.isString(args[0])) { const user = Cypress.env(`${args[0]}_username`) || args[0]; const password = Cypress.env(`${args[0]}_password`); if (user && password) { return authWithTenant({ user, password, userAlias: args[0], }); } } // getAuthOptions({user: "abc", password: "abc"}, ...) if (!_.isEmpty(args) && _.isObjectLike(args[0])) { if (isAuthOptions(args[0])) { return authWithTenant(_.pick(args[0], ["user", "password", "tenant", "userAlias", "type"])); } // getAuthOptions({userAlias: "abc"}, ...) if (args[0].userAlias) { const user = Cypress.env(`${args[0].userAlias}_username`) || args[0].userAlias; const password = Cypress.env(`${args[0].userAlias}_password`); if (user && password) { return authWithTenant({ user, password, userAlias: args[0].userAlias, ...(args[0].type && { type: args[0].type }), }); } } // getAuthOptions({user: "abc", password: "abc"}, ...) if (args[0].username && args[0].password) { const auth = _.pick(args[0], [ "username", "password", "tenantId", "userAlias", ]); delete Object.assign(auth, { user: auth.username })["username"]; if (auth.tenantId) { delete Object.assign(auth, { tenant: auth.tenantId })["tenantId"]; } return authWithTenant(auth); } // from IUser: getAuthOptions({userName: "abc", password: "abc"}, ...) if (args[0].userName && args[0].password) { const auth = _.pick(args[0], [ "userName", "password", "tenantId", "userAlias", ]); delete Object.assign(auth, { user: auth.userName })["userName"]; return authWithTenant(auth); } } // getAuthOptions("abc", "abc") if (args.length >= 2 && _.isString(args[0]) && _.isString(args[1])) { return authWithTenant({ user: args[0], password: args[1], }); } return undefined; } /** * Gets and implementation of IAuthentication from the given auth options. */ export function getC8yClientAuthentication(auth) { let authOptions; let result; if (auth) { if (_.isString(auth)) { authOptions = getAuthOptions(auth); } else if (_.isObjectLike(auth)) { if ("logout" in auth) { result = auth; } else { authOptions = auth; } } } if (!result) { const cookieAuth = new CookieAuth(); const token = get_i(cookieAuth.getFetchOptions({}), "headers.X-XSRF-TOKEN"); if (token?.trim() && !_.isEmpty(token.trim())) { result = cookieAuth; } else if (authOptions) { result = new BasicAuth(authOptions); } } return result; } export function persistAuth(auth) { const win = cy.state("window"); if (auth) { win.localStorage.setItem("__auth", JSON.stringify(auth)); } } export function tenantFromBasicAuth(auth) { if (!auth || !_.isObjectLike(auth) || !auth.user) return undefined; const components = auth.user.split("/"); if (!components || components.length < 2) return undefined; return components[0]; } function authWithTenant(options) { const tenant = Cypress.env(`C8Y_TENANT`); if (tenant && !options.tenant) { _.extend(options, { tenant }); } return options; } export function getSystemVersionFromEnv() { let result = toSemverVersion(Cypress.env(`C8Y_SYSTEM_VERSION`) || Cypress.env(`C8Y_VERSION`)); if (result == null && Cypress.c8ypact?.isEnabled() === true && Cypress.c8ypact.mode() === "mock") { const pactVersion = Cypress.c8ypact.current?.info.version?.system; if (pactVersion) { result = toSemverVersion(pactVersion); } } return result; } export function getShellVersionFromEnv() { return Cypress.env(`C8Y_SHELL_VERSION`); } /** * Tries to get the base URL from environment variables. The following * environment variables are checked in order: * - C8Y_BASEURL * - C8Y_BASE_URL * * @returns Base URL from environment variables. */ export function getBaseUrlFromEnv() { return (getEnvVar("C8Y_BASEURL") || getEnvVar("C8Y_BASE_URL") || Cypress.config().baseUrl || undefined); } export function storeClient(client) { cy.state("c8yclient", client); } export function restoreClient() { return cy.state("c8yclient"); } export function resetClient() { cy.state("c8yclient", undefined); } export function throwError(message) { const newErr = new Error(message); // newErr.name = "CypressError"; throw newErr; }